Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: net/tools/fetch/http_listen_socket.cc

Issue 99333: A utility driver for doing client/server HTTP transaction... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/tools/fetch/http_listen_socket.h ('k') | net/tools/fetch/http_server.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/compiler_specific.h"
6 #include "base/message_loop.h"
7 #include "base/string_util.h"
8 #include "net/tools/fetch/http_listen_socket.h"
9 #include "net/tools/fetch/http_server_request_info.h"
10 #include "net/tools/fetch/http_server_response_info.h"
11
12 // must run in the IO thread
13 HttpListenSocket::HttpListenSocket(SOCKET s,
14 HttpListenSocket::Delegate* delegate)
15 : ALLOW_THIS_IN_INITIALIZER_LIST(ListenSocket(s, this)),
16 delegate_(delegate) {
17 }
18
19 // must run in the IO thread
20 HttpListenSocket::~HttpListenSocket() {
21 }
22
23 void HttpListenSocket::Accept() {
24 SOCKET conn = ListenSocket::Accept(socket_);
25 DCHECK(conn != INVALID_SOCKET);
26 if (conn == INVALID_SOCKET) {
27 // TODO
28 } else {
29 scoped_refptr<HttpListenSocket> sock =
30 new HttpListenSocket(conn, delegate_);
31 // it's up to the delegate to AddRef if it wants to keep it around
32 DidAccept(this, sock);
33 }
34 }
35
36 HttpListenSocket* HttpListenSocket::Listen(const std::string& ip, int port,
37 HttpListenSocket::Delegate* delegate) {
38 SOCKET s = ListenSocket::Listen(ip, port);
39 if (s == INVALID_SOCKET) {
40 // TODO (ibrar): error handling
41 } else {
42 HttpListenSocket *serv = new HttpListenSocket(s, delegate);
43 serv->Listen();
44 return serv;
45 }
46 return NULL;
47 }
48
49 //
50 // HTTP Request Parser
51 // This HTTP request parser uses a simple state machine to quickly parse
52 // through the headers. The parser is not 100% complete, as it is designed
53 // for use in this simple test driver.
54 //
55 // Known issues:
56 // - does not handle whitespace on first HTTP line correctly. Expects
57 // a single space between the method/url and url/protocol.
58
59 // Input character types.
60 enum header_parse_inputs {
61 INPUT_SPACE,
62 INPUT_CR,
63 INPUT_LF,
64 INPUT_COLON,
65 INPUT_DEFAULT,
66 MAX_INPUTS
67 };
68
69 // Parser states.
70 enum header_parse_states {
71 ST_METHOD, // Receiving the method
72 ST_URL, // Receiving the URL
73 ST_PROTO, // Receiving the protocol
74 ST_HEADER, // Starting a Request Header
75 ST_NAME, // Receiving a request header name
76 ST_SEPARATOR, // Receiving the separator between header name and value
77 ST_VALUE, // Receiving a request header value
78 ST_DONE, // Parsing is complete and successful
79 ST_ERR, // Parsing encountered invalid syntax.
80 MAX_STATES
81 };
82
83 // State transition table
84 int parser_state[MAX_STATES][MAX_INPUTS] = {
85 /* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD },
86 /* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL },
87 /* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO },
88 /* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR },
89 /* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_SEPARATOR, ST_NAME },
90 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_SEPARATOR, ST_VALUE },
91 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE },
92 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE },
93 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR }
94 };
95
96 // Convert an input character to the parser's input token.
97 int charToInput(char ch) {
98 switch(ch) {
99 case ' ':
100 return INPUT_SPACE;
101 case '\r':
102 return INPUT_CR;
103 case '\n':
104 return INPUT_LF;
105 case ':':
106 return INPUT_COLON;
107 }
108 return INPUT_DEFAULT;
109 }
110
111 HttpServerRequestInfo* HttpListenSocket::ParseHeaders() {
112 int pos = 0;
113 int data_len = recv_data_.length();
114 int state = ST_METHOD;
115 HttpServerRequestInfo* info = new HttpServerRequestInfo();
116 std::string buffer;
117 std::string header_name;
118 std::string header_value;
119 while (pos < data_len) {
120 char ch = recv_data_[pos++];
121 int input = charToInput(ch);
122 int next_state = parser_state[state][input];
123
124 bool transition = (next_state != state);
125 if (transition) {
126 // Do any actions based on state transitions.
127 switch (state) {
128 case ST_METHOD:
129 info->method = buffer;
130 buffer.clear();
131 break;
132 case ST_URL:
133 info->url = GURL(buffer);
134 buffer.clear();
135 break;
136 case ST_PROTO:
137 // TODO(mbelshe): Deal better with parsing protocol.
138 DCHECK(buffer == "HTTP/1.1");
139 buffer.clear();
140 break;
141 case ST_NAME:
142 header_name = buffer;
143 buffer.clear();
144 break;
145 case ST_VALUE:
146 header_value = buffer;
147 // TODO(mbelshe): Deal better with duplicate headers
148 DCHECK(info->headers.find(header_name) == info->headers.end());
149 info->headers[header_name] = header_value;
150 buffer.clear();
151 break;
152 }
153 state = next_state;
154 } else {
155 // Do any actions based on current state
156 switch (state) {
157 case ST_METHOD:
158 case ST_URL:
159 case ST_PROTO:
160 case ST_VALUE:
161 case ST_NAME:
162 buffer.append(&ch, 1);
163 break;
164 case ST_DONE:
165 recv_data_ = recv_data_.substr(pos);
166 return info;
167 case ST_ERR:
168 delete info;
169 return NULL;
170 }
171 }
172 }
173 // No more characters, but we haven't finished parsing yet.
174 delete info;
175 return NULL;
176 }
177
178 void HttpListenSocket::DidAccept(ListenSocket* server,
179 ListenSocket* connection) {
180 connection->AddRef();
181 }
182
183 void HttpListenSocket::DidRead(ListenSocket* connection,
184 const std::string& data) {
185 recv_data_ += data;
186 while (recv_data_.length()) {
187 HttpServerRequestInfo* request = ParseHeaders();
188 if (!request)
189 break;
190 delegate_->OnRequest(this, request);
191 delete request;
192 }
193 }
194
195 void HttpListenSocket::DidClose(ListenSocket* sock) {
196 sock->Release();
197 }
198
199 // Convert the numeric status code to a string.
200 // e.g. 200 -> "200 OK"
201 std::string ServerStatus(int code) {
202 switch(code) {
203 case 200:
204 return std::string("200 OK");
205 // TODO(mbelshe): handle other codes.
206 }
207 NOTREACHED();
208 return std::string();
209 }
210
211 void HttpListenSocket::Respond(HttpServerResponseInfo* info,
212 std::string& data) {
213 std::string response;
214
215 // status line
216 response = info->protocol + " ";
217 response += ServerStatus(info->status);
218 response += "\r\n";
219
220 // standard headers
221 if (info->content_type.length())
222 response += "Content-type: " + info->content_type + "\r\n";
223
224 if (info->content_length > 0)
225 response += "Content-length: " + IntToString(info->content_length) +
226 "\r\n";
227
228 if (info->connection_close)
229 response += "Connection: close\r\n";
230
231 // TODO(mbelshe): support additional headers
232
233 // End of headers
234 response += "\r\n";
235
236 // Add data
237 response += data;
238
239 // Write it all out.
240 this->Send(response, false);
241 }
OLDNEW
« no previous file with comments | « net/tools/fetch/http_listen_socket.h ('k') | net/tools/fetch/http_server.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698