Assessment 1
Part A:
- This part is based on the content for the first two lab
- First we need to declare variables such as socket and cache
- Then I combine from the lab source and my own knowladge figure out the result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130/*************************************
* Filename: SMTPInteraction.java
*************************************/
import java.net.*;
import static java.lang.Integer.parseInt;
import java.io.*;
import java.util.*;
// Name: Junshu Sha
// ID: 201600804
// Blog: https://shaysha-pra.github.io/
// import jdk.internal.org.jline.utils.InputStreamReader;
/**
* Open an SMTP connection to mailserver and send one mail.
*
*/
public class SMTPInteraction {
/* Socket to the server */
private Socket connection;
/* Streams for reading from and writing to socket */
private BufferedReader fromServer;
private DataOutputStream toServer;
private static final String CRLF = "\r\n";
/* Are we connected? Used in close() to determine what to do. */
//the number of recipient address
private boolean isConnected = false;
private int number_of_RCPT = 0;
private String check_RCPT[];
/* Create an SMTPInteraction object. Create the socket and the
associated streams. Initialise SMTP connection. */
public SMTPInteraction(EmailMessage mailmessage) throws IOException {
// Open a TCP client socket with hostname and portnumber specified in
// mailmessage.DestHost and mailmessage.DestHostPort, respectively.
int PORT = mailmessage. DestHostPort;
connection = new Socket(mailmessage.DestHost, PORT);
// attach the BufferedReader fromServer to read from the socket and
// the DataOutputStream toServer to write to the socket
fromServer = new BufferedReader(new InputStreamReader(connection.getInputStream()));
toServer = new DataOutputStream(connection.getOutputStream());
// fromServer = new BufferedReader(new InputStreamReader(System.in));
// toServer = System.out;
/* Read one line from server and check that the reply code is 220.
If not, throw an IOException. */
String response = fromServer.readLine();
if (!response.startsWith("220")) {
throw new IOException("220 reply not received from server.");
}
/* SMTP handshake. We need the name of the local machine.
Send the appropriate SMTP handshake command. */
String localhost = InetAddress.getLocalHost().getHostName();
sendCommand("HELO " + localhost, 250);
isConnected = true;
}
/* Send message. Write the correct SMTP-commands in the
correct order. No checking for errors, just throw them to the
caller. */
public void send(EmailMessage mailmessage) throws IOException {
// initialize the number of rcpt address.
check_RCPT = mailmessage.Recipient.split(",");
number_of_RCPT = check_RCPT.length;
/* Send all the necessary commands to send a message. Call
sendCommand() to do the dirty work. Do _not_ catch the
exception thrown from sendCommand(). */
sendCommand(("MAIL FROM: " + "<" + mailmessage.Sender+ ">"), 250);
if (number_of_RCPT > 1){
for (int i = 0; i <= number_of_RCPT;i++){
sendCommand(("RCPT TO: " + "<" + check_RCPT[i] + ">"), 250);
number_of_RCPT--;
}
}else{
sendCommand(("RCPT TO: " + "<" + mailmessage.Recipient + ">"), 250);
}
sendCommand("DATA", 354);
sendCommand(mailmessage.Headers + CRLF + mailmessage.Body + CRLF + ".", 250);
}
/* Close SMTP connection. First, terminate on SMTP level, then
close the socket. */
public void close() {
isConnected = false;
try {
sendCommand("QUIT", 221);
connection.close();
} catch (IOException e) {
System.out.println("Unable to close connection: " + e);
isConnected = true;
}
}
/* Send an SMTP command to the server. Check that the reply code is
what is is supposed to be according to RFC 821. */
private void sendCommand(String command, int rc) throws IOException {
/* Write command to server and read reply from server. */
toServer.writeBytes(command + CRLF);
/* Check that the server's reply code is the same as the parameter
rc. If not, throw an IOException. */
String response = fromServer.readLine().split(" ")[0];
int reply_code = parseInt(response);
System.out.println(response);
if(reply_code != rc)
throw new IOException("reply code is not matched.");
}
protected void finalize() throws Throwable {
if (isConnected) {
close();
}
}
}
Part B
- This part is the application of the HTTP method
- This part is some functional functions. The function I used to judge BUF_SIZE at the beginning is logically wrong. This is very common and it is difficult to find that after a long time of inspection, I changed to the function that I use now.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197/**********************************
* Filename: HTTPInteraction.java
*************************************/
import java.io.*;
import java.net.*;
import java.util.*;
// Name: Junshu Sha
// ID: 201600804
// Blog: https://shaysha-pra.github.io/
// import jdk.internal.org.jline.utils.InputStreamReader;
/**
* Class for downloading one object from http server.
*
*/
public class HTTPInteraction {
private String host;
private String path;
private String requestMessage;
private static final int HTTP_PORT = 80;
private static final String CRLF = "\r\n";
private static final int BUF_SIZE = 4096;
private static final int MAX_OBJECT_SIZE = 102400;
/* Create HTTPInteraction object. */
public HTTPInteraction(String url) {
/* Split "URL" into "host name" and "path name", and
* set host and path class variables.
* if the URL is only a host name, use "/" as path
*/
/* Fill in */
String name[] = url.split("/", 2); // divided url into two parts when it meets the first "/"
host = name[0]; // initial the host as first part of name[]
if (name.length >= 2) {
path = "/" + name[1]; // set path name when name's length is bigger or equal than 2
}else{
path = "/";
}
/* Construct requestMessage, add a header line so that
* server closes connection after one response. */
requestMessage = "GET " + path + " HTTP/1.1" + CRLF + "Host: " + host + CRLF; // normal format for GET method
return;
}
/* Send Http request, parse response and return requested object
* as a String (if no errors),
* otherwise return meaningful error message.
* Don't catch Exceptions. EmailClient will handle them. */
public String send() throws IOException {
/* buffer to read object in 4kB chunks */
char[] buf = new char[BUF_SIZE];
/* Maximum size of object is 100kB, which should be enough for most objects.
* Change constant if you need more. */
char[] body = new char[MAX_OBJECT_SIZE];
String statusLine=""; // status line
int status; // status code
String headers=""; // headers
int bodyLength=-1; // lenghth of body
String[] tmp;
/* The socket to the server */
Socket connection;
/* Streams for reading from and writing to socket */
BufferedReader fromServer;
DataOutputStream toServer;
System.out.println("Connecting server: " + host +CRLF);
/* Connect to http server on port 80.
* Assign input and output streams to connection. */
connection = new Socket(host, HTTP_PORT); // get host and it's server
fromServer = new BufferedReader(new InputStreamReader(connection.getInputStream())); // get input of connection
toServer = new DataOutputStream(connection.getOutputStream()); // get out put of connection
System.out.println("Send request:\n" + requestMessage); //print request Message
/* Send requestMessage to http server */
/* Fill in */
toServer.writeBytes(requestMessage + CRLF);
/* Read the status line from response message */
statusLine= fromServer.readLine();
System.out.println("Status Line:\n"+ statusLine +CRLF); //print status message
/* Extract status code from status line. If status code is not 200,
* close connection and return an error message.
* Do NOT throw an exception */
/* Fill in */
status = Integer.parseInt(statusLine.substring(9,12)); // get status codes
try{ // this part is almost same as the lab session
if (status != 200){
connection.close();
System.out.println("status code is not 200!");
}
}catch(UnknownHostException e){
throw e;
}
/* Read header lines from response message, convert to a string,
* and assign to "headers" variable.
* Recall that an empty line indicates end of headers.
* Extract length from "Content-Length:" (or "Content-length:")
* header line, if present, and assign to "bodyLength" variable.
*/
/* Fill in */ // requires about 10 lines of code
String header_lines;
while(!(header_lines = fromServer.readLine()).isEmpty()){
headers += header_lines + CRLF; // generate the hearder's information
if(header_lines.startsWith("Content-Length:") || header_lines.startsWith("content-length:")){
tmp = header_lines.split(" ");
int lth = Integer.parseInt(tmp[1]);
bodyLength = lth;
}
if (header_lines.startsWith("Location:")) {
tmp = header_lines.split(" ");
return tmp[1];
}
}
System.out.println("Headers:\n" + headers + CRLF);
/* If object is larger than MAX_OBJECT_SIZE, close the connection and
* return meaningful message. */
if (bodyLength > MAX_OBJECT_SIZE) {
/* Fill in */
connection.close();
return(headers +bodyLength);
}
/* Read the body in chunks of BUF_SIZE using buf[] and copy the chunk
* into body[]. Stop when either we have
* read Content-Length bytes or when the connection is
* closed (when there is no Content-Length in the response).
* Use one of the read() methods of BufferedReader here, NOT readLine().
* Make sure not to read more than MAX_OBJECT_SIZE characters.
*/
int bytesRead = 0;
/* Fill in */ // Requires 10-20 lines of code
if(bodyLength>0){ //Read the body in chunks of BUF_SIZE using buf[] and copy the chunk in to body[]
while(bodyLength-bytesRead>0){
int read = fromServer.read(buf); // read form buf
for(int i=0;i< read;i++){
body[i+bytesRead] = buf[i];
}
bytesRead += read; // add read's content to bytesRead
}
}else{
while(bytesRead<MAX_OBJECT_SIZE){
int read = fromServer.read(buf, 0, BUF_SIZE);
if(read == -1) break;
for(int i=0;i< read;i++){
body[i+bytesRead] = buf[i];
}
bytesRead += read;
}
}
for(int i=0;i<bytesRead;i++){
System.out.print(body[i]);
}
/* At this points body[] should hold to body of the downloaded object and
* bytesRead should hold the number of bytes read from the BufferedReader
*/
/* Close connection and return object as String. */
System.out.println("Done reading file. Closing connection.");
connection.close();
return(new String(body, 0, bytesRead));
}
}