OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "entd/callback_server.h" | 5 #include "entd/callback_server.h" |
6 | 6 |
7 #include <base/scoped_ptr.h> | 7 #include <base/scoped_ptr.h> |
8 | 8 |
9 #include "entd/entd.h" | 9 #include "entd/entd.h" |
10 | 10 |
11 namespace entd { | 11 namespace entd { |
12 | 12 |
13 using std::string; | 13 using std::string; |
14 | 14 |
| 15 std::string CallbackServer::session_id_; |
| 16 |
15 namespace { | 17 namespace { |
16 // Max 1k request entity | 18 // Max 1k request entity |
17 const int kMaxRequestSize = 1024; | 19 const int kMaxRequestSize = 1024; |
18 | 20 |
19 // libevent defines some of these but not all, so we define what we need here | 21 // libevent defines some of these but not all, so we define what we need here |
20 const int kHttpOk = 200; | 22 const int kHttpOk = 200; |
21 const int kHttpBadRequest = 400; | 23 const int kHttpBadRequest = 400; |
22 const int kHttpNotFound = 404; | 24 const int kHttpNotFound = 404; |
23 const int kHttpBadMethod = 405; | 25 const int kHttpBadMethod = 405; |
24 const int kHttpBadEntitySize = 413; | 26 const int kHttpBadEntitySize = 413; |
25 const int kHttpBadMedia = 415; | 27 const int kHttpBadMedia = 415; |
26 const int kHttpServerError = 500; | 28 const int kHttpServerError = 500; |
27 | 29 |
28 const uint32_t kDefaultPort = 5199; // Atomic weight of Cr, sorta | 30 const uint32_t kDefaultPort = 5199; // Atomic weight of Cr, sorta |
29 const uint32_t kMinPort = 5000; | 31 const uint32_t kMinPort = 5000; |
30 const uint32_t kMaxPort = 5999; | 32 const uint32_t kMaxPort = 5999; |
31 | 33 |
32 // Incoming requests must have this content type | 34 // Incoming requests must have this content type |
33 const std::string kContentType = "application/json; charset=UTF-8"; | 35 const std::string kContentType = "application/json; charset=UTF-8"; |
34 | 36 |
35 // Default value of request_header_value_ | |
36 const std::string kDefaultRequestHeaderValue = "magic"; | |
37 | |
38 // Callback functions must have this prefix, so we can avoid dispatching | 37 // Callback functions must have this prefix, so we can avoid dispatching |
39 // against default properties that aren't actually intended to be callbacks. | 38 // against default properties that aren't actually intended to be callbacks. |
40 const std::string kCallbackPrefix = "cb:"; | 39 const std::string kCallbackPrefix = "cb:"; |
41 | 40 |
42 // Called by libevent when it accepts an http request. | 41 // Called by libevent when it accepts an http request. |
43 void dispatch_OnRequest(struct evhttp_request* request, void* data) { | 42 void dispatch_OnRequest(struct evhttp_request* request, void* data) { |
44 CallbackServer* cbs = reinterpret_cast<CallbackServer*>(data); | 43 CallbackServer* cbs = reinterpret_cast<CallbackServer*>(data); |
45 cbs->SetBusy(true); | 44 cbs->SetBusy(true); |
46 cbs->OnRequest(request); | 45 cbs->OnRequest(request); |
47 cbs->SetBusy(false); | 46 cbs->SetBusy(false); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 if (cs->IsBusy()) { | 100 if (cs->IsBusy()) { |
102 utils::ThrowV8Exception("Can't stop server while busy"); | 101 utils::ThrowV8Exception("Can't stop server while busy"); |
103 return v8::Undefined(); | 102 return v8::Undefined(); |
104 } | 103 } |
105 | 104 |
106 cs->Stop(); | 105 cs->Stop(); |
107 | 106 |
108 return v8::Undefined(); | 107 return v8::Undefined(); |
109 } | 108 } |
110 | 109 |
111 // Called by v8 when someone trys to read from callbackServer.requestHeaderValue | |
112 v8::Handle<v8::Value> dispatch_GetRequestHeaderValue( | |
113 v8::Local<v8::String> name, | |
114 const v8::AccessorInfo& info) { | |
115 CallbackServer* cs = CallbackServer::Unwrap(info.Holder()); | |
116 return v8::String::New(cs->request_header_value().c_str()); | |
117 } | |
118 | |
119 // Called by v8 when someone trys to assign to callbackServer.requestHeaderValue | |
120 void dispatch_SetRequestHeaderValue(v8::Local<v8::String> name, | |
121 v8::Local<v8::Value> value, | |
122 const v8::AccessorInfo& info) { | |
123 CallbackServer* cs = CallbackServer::Unwrap(info.Holder()); | |
124 cs->set_request_header_value(*v8::String::Utf8Value(value)); | |
125 } | |
126 | |
127 } // namespace | 110 } // namespace |
128 | 111 |
129 std::string CallbackServer::required_origin = ""; | 112 std::string CallbackServer::required_origin = ""; |
130 | 113 |
131 CallbackServer::CallbackServer(Entd* entd) | 114 CallbackServer::CallbackServer(Entd* entd) |
132 : busy_(false), | 115 : busy_(false), |
133 entd_(entd), | 116 entd_(entd), |
134 request_header_value_(kDefaultRequestHeaderValue), | |
135 evhttp_(NULL) | 117 evhttp_(NULL) |
136 {} | 118 {} |
137 | 119 |
138 CallbackServer::~CallbackServer() { | 120 CallbackServer::~CallbackServer() { |
139 CleanupTemplate(); | 121 CleanupTemplate(); |
140 Stop(); | 122 Stop(); |
141 } | 123 } |
142 | 124 |
143 // static | 125 // static |
144 void CallbackServer::SetTemplateBindings( | 126 void CallbackServer::SetTemplateBindings( |
145 v8::Handle<v8::ObjectTemplate> template_object) { | 127 v8::Handle<v8::ObjectTemplate> template_object) { |
146 template_object->Set(v8::String::NewSymbol("start"), | 128 template_object->Set(v8::String::NewSymbol("start"), |
147 v8::FunctionTemplate::New(dispatch_Start)); | 129 v8::FunctionTemplate::New(dispatch_Start)); |
148 template_object->Set(v8::String::NewSymbol("stop"), | 130 template_object->Set(v8::String::NewSymbol("stop"), |
149 v8::FunctionTemplate::New(dispatch_Stop)); | 131 v8::FunctionTemplate::New(dispatch_Stop)); |
150 template_object->SetAccessor(v8::String::NewSymbol("requestHeaderValue"), | |
151 dispatch_GetRequestHeaderValue, | |
152 dispatch_SetRequestHeaderValue); | |
153 } | 132 } |
154 | 133 |
155 void CallbackServer::OnRequest(struct evhttp_request* request) { | 134 void CallbackServer::OnRequest(struct evhttp_request* request) { |
156 const char* uri = evhttp_request_uri(request); | 135 const char* uri = evhttp_request_uri(request); |
157 | 136 |
158 // It might be nicer (certainly more RESTful) if the function were part | 137 // It might be nicer (certainly more RESTful) if the function were part |
159 // of the URI, but that would be more parsing which might add to the | 138 // of the URI, but that would be more parsing which might add to the |
160 // exploitability of this code. Instead we only accept requests for | 139 // exploitability of this code. Instead we only accept requests for |
161 // "/dispatch", and leave the parsing to v8's native JSON parser. | 140 // "/dispatch", and leave the parsing to v8's native JSON parser. |
162 if (strcmp("/dispatch", uri) != 0) { | 141 if (strcmp("/dispatch", uri) != 0) { |
(...skipping 13 matching lines...) Expand all Loading... |
176 // Content type must be json. We won't be doing any form parsing, | 155 // Content type must be json. We won't be doing any form parsing, |
177 // multipart or otherwise. | 156 // multipart or otherwise. |
178 const char* header = evhttp_find_header(request->input_headers, | 157 const char* header = evhttp_find_header(request->input_headers, |
179 "Content-Type"); | 158 "Content-Type"); |
180 if (!header || strcmp(kContentType.c_str(), header) != 0) { | 159 if (!header || strcmp(kContentType.c_str(), header) != 0) { |
181 LOG(ERROR) << "Invalid Content-Type: " << header; | 160 LOG(ERROR) << "Invalid Content-Type: " << header; |
182 evhttp_send_error(request, kHttpBadMedia, "Bad Content-Type"); | 161 evhttp_send_error(request, kHttpBadMedia, "Bad Content-Type"); |
183 return; | 162 return; |
184 } | 163 } |
185 | 164 |
186 // This header must be present, since Chrome's XMLHttpRequest object | 165 // Check the session ID. |
187 // won't let you set an unknown header for cross domain XHR. | 166 header = evhttp_find_header(request->input_headers, "X-Entd-Session-Id"); |
188 header = evhttp_find_header(request->input_headers, "X-Entd-Request"); | 167 if (!header || header != session_id_) { |
189 if (!header || strcmp(request_header_value_.c_str(), header) != 0) { | 168 LOG(ERROR) << "Bad or missing X-Entd-Session-Id header: " << header; |
190 LOG(ERROR) << "Bad or missing X-Entd-Request header"; | 169 evhttp_send_error(request, kHttpBadRequest, |
191 evhttp_send_error(request, kHttpBadRequest, "Bad X-Entd-Request header"); | 170 "Bad or missing session id header"); |
192 return; | 171 return; |
193 } | 172 } |
194 | 173 |
195 if (!CallbackServer::required_origin.empty()) { | 174 if (!CallbackServer::required_origin.empty()) { |
196 header = evhttp_find_header(request->input_headers, "Origin"); | 175 header = evhttp_find_header(request->input_headers, "Origin"); |
197 if (!header || | 176 if (!header || |
198 strcmp(CallbackServer::required_origin.c_str(), header) != 0) { | 177 strcmp(CallbackServer::required_origin.c_str(), header) != 0) { |
199 LOG(ERROR) << "Bad or missing Origin header: " << header; | 178 LOG(ERROR) << "Bad or missing Origin header: " << header; |
200 evhttp_send_error(request, kHttpBadRequest, | 179 evhttp_send_error(request, kHttpBadRequest, |
201 "Bad or missing Origin header"); | 180 "Bad or missing Origin header"); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 evhttp_ = NULL; | 324 evhttp_ = NULL; |
346 port_ = 0; | 325 port_ = 0; |
347 callbacks_.Dispose(); | 326 callbacks_.Dispose(); |
348 } | 327 } |
349 | 328 |
350 bool CallbackServer::IsRunning() { | 329 bool CallbackServer::IsRunning() { |
351 return evhttp_ != NULL; | 330 return evhttp_ != NULL; |
352 } | 331 } |
353 | 332 |
354 } // namespace entd | 333 } // namespace entd |
OLD | NEW |