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