OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 #include "chrome/test/webdriver/dispatch.h" |
| 5 |
| 6 #include <sstream> |
| 7 #include <string> |
| 8 |
| 9 #include "base/json/json_writer.h" |
| 10 #include "chrome/test/webdriver/commands/command.h" |
| 11 |
| 12 namespace webdriver { |
| 13 |
| 14 // The standard HTTP Status codes are implemented below. Chrome uses |
| 15 // OK, See Other, Not Found, Method Not Allowed, and Internal Error. |
| 16 // Internal Error, HTTP 500, is used as a catch all for any issue |
| 17 // not covered in the JSON protocol. |
| 18 void SendHttpOk(struct mg_connection* const connection, |
| 19 const struct mg_request_info* const request_info, |
| 20 const Response& response) { |
| 21 const std::string json = response.ToJSON(); |
| 22 std::ostringstream out; |
| 23 out << "HTTP/1.1 200 OK\r\n" |
| 24 << "Content-Length: " << strlen(json.c_str()) << "\r\n" |
| 25 << "Content-Type: application/json; charset=UTF-8\r\n" |
| 26 << "Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept\r\n" |
| 27 << "Accept-Ranges: bytes\r\n" |
| 28 << "Connection: close\r\n\r\n"; |
| 29 if (strcmp(request_info->request_method, "HEAD") != 0) { |
| 30 out << json << "\r\n"; |
| 31 } |
| 32 LOG(INFO) << out.str() << std::endl; |
| 33 mg_printf(connection, "%s", out.str().c_str()); |
| 34 } |
| 35 |
| 36 void SendHttpSeeOther(struct mg_connection* const connection, |
| 37 const struct mg_request_info* const request_info, |
| 38 const Response& response) { |
| 39 const Value* value = response.value(); |
| 40 CheckValueType(Value::TYPE_STRING, value); |
| 41 std::string location; |
| 42 if (!value->GetAsString(&location)) { |
| 43 NOTREACHED(); |
| 44 } |
| 45 |
| 46 std::ostringstream out; |
| 47 out << "HTTP/1.1 303 See Other\r\n" |
| 48 << "Location: " << location << "\r\n" |
| 49 << "Content-Type: text/html\r\n" |
| 50 << "Content-Length: 0\r\n\r\n"; |
| 51 LOG(INFO) << out.str() << std::endl; |
| 52 mg_printf(connection, "%s", out.str().c_str()); |
| 53 } |
| 54 |
| 55 void SendHttpBadRequest(struct mg_connection* const connection, |
| 56 const struct mg_request_info* const request_info, |
| 57 const Response& response) { |
| 58 const std::string json = response.ToJSON(); |
| 59 std::ostringstream out; |
| 60 out << "HTTP/1.1 400 Bad Request\r\n" |
| 61 << "Content-Length: " << strlen(json.c_str()) << "\r\n" |
| 62 << "Content-Type: application/json; charset=UTF-8\r\n" |
| 63 << "Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept\r\n" |
| 64 << "Accept-Ranges: bytes\r\n" |
| 65 << "Connection: close\r\n\r\n"; |
| 66 if (strcmp(request_info->request_method, "HEAD") != 0) { |
| 67 out << json << "\r\n"; |
| 68 } |
| 69 LOG(INFO) << out.str() << std::endl; |
| 70 mg_printf(connection, "%s", out.str().c_str()); |
| 71 } |
| 72 |
| 73 void SendHttpNotFound(struct mg_connection* const connection, |
| 74 const struct mg_request_info* const request_info, |
| 75 const Response& response) { |
| 76 const std::string json = response.ToJSON(); |
| 77 std::ostringstream out; |
| 78 out << "HTTP/1.1 404 Not Found\r\n" |
| 79 << "Content-Length: " << strlen(json.c_str()) << "\r\n" |
| 80 << "Content-Type: application/json; charset=UTF-8\r\n" |
| 81 << "Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept\r\n" |
| 82 << "Accept-Ranges: bytes\r\n" |
| 83 << "Connection: close\r\n\r\n"; |
| 84 if (strcmp(request_info->request_method, "HEAD") != 0) { |
| 85 out << json << "\r\n"; |
| 86 } |
| 87 LOG(INFO) << out.str() << std::endl; |
| 88 mg_printf(connection, "%s", out.str().c_str()); |
| 89 } |
| 90 |
| 91 void SendHttpMethodNotAllowed(struct mg_connection* const connection, |
| 92 const struct mg_request_info* const request_info, |
| 93 const Response& response) { |
| 94 const Value* value = response.value(); |
| 95 CheckValueType(Value::TYPE_LIST, value); |
| 96 |
| 97 std::vector<std::string> allowed_methods; |
| 98 const ListValue* list_value = static_cast<const ListValue*>(value); |
| 99 for (size_t i = 0; i < list_value->GetSize(); ++i) { |
| 100 std::string method; |
| 101 LOG_IF(WARNING, list_value->GetString(i, &method)) |
| 102 << "Ignoring non-string value at index " << i; |
| 103 allowed_methods.push_back(method); |
| 104 } |
| 105 |
| 106 std::ostringstream out; |
| 107 out << "HTTP/1.1 405 Method Not Allowed\r\n" |
| 108 << "Content-Type: text/html\r\n" |
| 109 << "Content-Length: 0\r\n" |
| 110 << "Allow: " << JoinString(allowed_methods, ',') << "\r\n\r\n"; |
| 111 LOG(INFO) << out.str() << std::endl; |
| 112 mg_printf(connection, "%s", out.str().c_str()); |
| 113 } |
| 114 |
| 115 void SendHttpInternalError(struct mg_connection* const connection, |
| 116 const struct mg_request_info* const request_info, |
| 117 const Response& response) { |
| 118 const std::string json = response.ToJSON(); |
| 119 std::ostringstream out; |
| 120 out << "HTTP/1.1 500 Internal Server Error\r\n" |
| 121 << "Content-Length: " << strlen(json.c_str()) << "\r\n" |
| 122 << "Content-Type: application/json; charset=UTF-8\r\n" |
| 123 << "Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept\r\n" |
| 124 << "Accept-Ranges: bytes\r\n" |
| 125 << "Connection: close\r\n\r\n"; |
| 126 if (strcmp(request_info->request_method, "HEAD") != 0) { |
| 127 out << json << "\r\n"; |
| 128 } |
| 129 LOG(INFO) << out.str() << std::endl; |
| 130 mg_printf(connection, "%s", out.str().c_str()); |
| 131 } |
| 132 |
| 133 // For every HTTP request from the mongoode server DispatchCommand will |
| 134 // inspect the HTTP method call requested and execute the proper function |
| 135 // mapped from the class Command. |
| 136 void DispatchCommand(Command* const command, const std::string& method, |
| 137 Response* response) { |
| 138 if (command->DoesPost() && method == "POST") { |
| 139 if (command->Init(response)) { |
| 140 command->ExecutePost(response); |
| 141 } |
| 142 } else if (command->DoesGet() && method == "GET") { |
| 143 if (command->Init(response)) { |
| 144 command->ExecuteGet(response); |
| 145 } |
| 146 } else if (command->DoesDelete() && method == "DELETE") { |
| 147 if (command->Init(response)) { |
| 148 command->ExecuteDelete(response); |
| 149 } |
| 150 } else { |
| 151 ListValue* methods = new ListValue; |
| 152 if (command->DoesPost()) { |
| 153 methods->Append(Value::CreateStringValue("POST")); |
| 154 } |
| 155 if (command->DoesGet()) { |
| 156 methods->Append(Value::CreateStringValue("GET")); |
| 157 methods->Append(Value::CreateStringValue("HEAD")); |
| 158 } |
| 159 if (command->DoesDelete()) { |
| 160 methods->Append(Value::CreateStringValue("DELETE")); |
| 161 } |
| 162 response->set_status(kMethodNotAllowed); |
| 163 response->set_value(methods); // Assumes ownership. |
| 164 } |
| 165 } |
| 166 |
| 167 void SendResponse(struct mg_connection* const connection, |
| 168 const struct mg_request_info* const request_info, |
| 169 const Response& response) { |
| 170 switch (response.status()) { |
| 171 case kSuccess: |
| 172 SendHttpOk(connection, request_info, response); |
| 173 break; |
| 174 |
| 175 case kSeeOther: |
| 176 SendHttpSeeOther(connection, request_info, response); |
| 177 break; |
| 178 |
| 179 case kBadRequest: |
| 180 SendHttpBadRequest(connection, request_info, response); |
| 181 break; |
| 182 |
| 183 case kSessionNotFound: |
| 184 SendHttpNotFound(connection, request_info, response); |
| 185 break; |
| 186 |
| 187 case kMethodNotAllowed: |
| 188 SendHttpMethodNotAllowed(connection, request_info, response); |
| 189 break; |
| 190 |
| 191 // All other errors should be treated as generic 500s. The client will be |
| 192 // responsible for inspecting the message body for details. |
| 193 default: |
| 194 SendHttpInternalError(connection, request_info, response); |
| 195 break; |
| 196 } |
| 197 } |
| 198 } // namespace webdriver |
| 199 |
OLD | NEW |