blob: af10968b8ceed7da6a0a866ead916c167948752e [file] [log] [blame]
adlr@google.com3defe6a2009-12-04 20:57:17 +00001// Copyright (c) 2009 The Chromium OS 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// This file implements a simple HTTP server. It can exhibit odd behavior
6// that's useful for testing. For example, it's useful to test that
7// the updater can continue a connection if it's dropped, or that it
8// handles very slow data transfers.
9
10// To use this, simply make an HTTP connection to localhost:port and
11// GET a url.
12
adlr@google.com3defe6a2009-12-04 20:57:17 +000013#include <errno.h>
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070014#include <inttypes.h>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070015#include <netinet/in.h>
16#include <signal.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000017#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070020#include <sys/socket.h>
21#include <sys/types.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000022#include <unistd.h>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070023
adlr@google.com3defe6a2009-12-04 20:57:17 +000024#include <algorithm>
25#include <string>
26#include <vector>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070027
28#include <base/logging.h>
Gilad Arnold9bedeb52011-11-17 16:19:57 -080029#include <base/string_split.h>
30#include <base/string_util.h>
31
32#include "update_engine/http_common.h"
33#include "update_engine/http_fetcher_unittest.h"
34
adlr@google.com3defe6a2009-12-04 20:57:17 +000035
Gilad Arnolde4ad2502011-12-29 17:08:54 -080036// HTTP end-of-line delimiter; sorry, this needs to be a macro.
37#define EOL "\r\n"
38
adlr@google.com3defe6a2009-12-04 20:57:17 +000039using std::min;
40using std::string;
41using std::vector;
42
Gilad Arnold9bedeb52011-11-17 16:19:57 -080043
adlr@google.com3defe6a2009-12-04 20:57:17 +000044namespace chromeos_update_engine {
45
46struct HttpRequest {
Gilad Arnolde4ad2502011-12-29 17:08:54 -080047 HttpRequest()
48 : start_offset(0), end_offset(0), return_code(kHttpResponseOk) {}
Darin Petkov41c2fcf2010-08-25 13:14:48 -070049 string host;
adlr@google.com3defe6a2009-12-04 20:57:17 +000050 string url;
Gilad Arnold9bedeb52011-11-17 16:19:57 -080051 off_t start_offset;
Gilad Arnolde4ad2502011-12-29 17:08:54 -080052 off_t end_offset; // non-inclusive, zero indicates unspecified.
Gilad Arnold9bedeb52011-11-17 16:19:57 -080053 HttpResponseCode return_code;
adlr@google.com3defe6a2009-12-04 20:57:17 +000054};
55
adlr@google.com3defe6a2009-12-04 20:57:17 +000056bool ParseRequest(int fd, HttpRequest* request) {
57 string headers;
Gilad Arnold9bedeb52011-11-17 16:19:57 -080058 do {
59 char buf[1024];
60 ssize_t r = read(fd, buf, sizeof(buf));
adlr@google.com3defe6a2009-12-04 20:57:17 +000061 if (r < 0) {
62 perror("read");
63 exit(1);
64 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -080065 headers.append(buf, r);
66 } while (!EndsWith(headers, EOL EOL, true));
adlr@google.com3defe6a2009-12-04 20:57:17 +000067
Gilad Arnold9bedeb52011-11-17 16:19:57 -080068 LOG(INFO) << "got headers:\n--8<------8<------8<------8<----\n"
69 << headers
70 << "\n--8<------8<------8<------8<----";
adlr@google.com3defe6a2009-12-04 20:57:17 +000071
Gilad Arnold9bedeb52011-11-17 16:19:57 -080072 // Break header into lines.
73 std::vector<string> lines;
74 base::SplitStringUsingSubstr(
75 headers.substr(0, headers.length() - strlen(EOL EOL)), EOL, &lines);
adlr@google.com3defe6a2009-12-04 20:57:17 +000076
Gilad Arnold9bedeb52011-11-17 16:19:57 -080077 // Decode URL line.
78 std::vector<string> terms;
79 base::SplitStringAlongWhitespace(lines[0], &terms);
80 CHECK_EQ(terms.size(), 3);
81 CHECK_EQ(terms[0], "GET");
82 request->url = terms[1];
83 LOG(INFO) << "URL: " << request->url;
adlr@google.com3defe6a2009-12-04 20:57:17 +000084
Gilad Arnold9bedeb52011-11-17 16:19:57 -080085 // Decode remaining lines.
86 size_t i;
87 for (i = 1; i < lines.size(); i++) {
88 std::vector<string> terms;
89 base::SplitStringAlongWhitespace(lines[i], &terms);
Darin Petkov41c2fcf2010-08-25 13:14:48 -070090
Gilad Arnold9bedeb52011-11-17 16:19:57 -080091 if (terms[0] == "Range:") {
92 CHECK_EQ(terms.size(), 2);
93 string &range = terms[1];
94 LOG(INFO) << "range attribute: " << range;
95 CHECK(StartsWithASCII(range, "bytes=", true) &&
Gilad Arnolde4ad2502011-12-29 17:08:54 -080096 range.find('-') != string::npos);
Gilad Arnold9bedeb52011-11-17 16:19:57 -080097 request->start_offset = atoll(range.c_str() + strlen("bytes="));
Gilad Arnolde4ad2502011-12-29 17:08:54 -080098 // Decode end offset and increment it by one (so it is non-inclusive).
99 if (range.find('-') < range.length() - 1)
100 request->end_offset = atoll(range.c_str() + range.find('-') + 1) + 1;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800101 request->return_code = kHttpResponsePartialContent;
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800102 std::string tmp_str = StringPrintf("decoded range offsets: start=%jd "
103 "end=", request->start_offset);
104 if (request->end_offset > 0)
105 base::StringAppendF(&tmp_str, "%jd (non-inclusive)",
106 request->end_offset);
107 else
108 base::StringAppendF(&tmp_str, "unspecified");
109 LOG(INFO) << tmp_str;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800110 } else if (terms[0] == "Host:") {
111 CHECK_EQ(terms.size(), 2);
112 request->host = terms[1];
113 LOG(INFO) << "host attribute: " << request->host;
114 } else {
115 LOG(WARNING) << "ignoring HTTP attribute: `" << lines[i] << "'";
adlr@google.com3defe6a2009-12-04 20:57:17 +0000116 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000117 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800118
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700119 return true;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000120}
121
122string Itoa(off_t num) {
123 char buf[100] = {0};
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700124 snprintf(buf, sizeof(buf), "%" PRIi64, num);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000125 return buf;
126}
127
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800128// Writes a string into a file. Returns total number of bytes written or -1 if a
129// write error occurred.
130ssize_t WriteString(int fd, const string& str) {
131 const size_t total_size = str.size();
132 size_t remaining_size = total_size;
133 char const *data = str.data();
Gilad Arnold48085ba2011-11-16 09:36:08 -0800134
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800135 while (remaining_size) {
136 ssize_t written = write(fd, data, remaining_size);
137 if (written < 0) {
138 perror("write");
139 LOG(INFO) << "write failed";
140 return -1;
141 }
142 data += written;
143 remaining_size -= written;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000144 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800145
146 return total_size;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000147}
148
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800149// Writes the headers of an HTTP response into a file.
150ssize_t WriteHeaders(int fd, const off_t start_offset, const off_t end_offset,
151 HttpResponseCode return_code) {
152 ssize_t written = 0, ret;
153
154 ret = WriteString(fd,
155 string("HTTP/1.1 ") + Itoa(return_code) + " " +
156 GetHttpResponseDescription(return_code) +
157 EOL
158 "Content-Type: application/octet-stream" EOL);
159 if (ret < 0)
160 return -1;
161 written += ret;
162
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800163 // Compute content legnth.
164 const off_t content_length = end_offset - start_offset;;
165
166 // A start offset that equals the end offset indicates that the response
167 // should contain the full range of bytes in the requested resource.
168 if (start_offset || start_offset == end_offset) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800169 ret = WriteString(fd,
170 string("Accept-Ranges: bytes" EOL
171 "Content-Range: bytes ") +
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800172 Itoa(start_offset == end_offset ? 0 : start_offset) +
173 "-" + Itoa(end_offset - 1) + "/" + Itoa(end_offset) +
174 EOL);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800175 if (ret < 0)
176 return -1;
177 written += ret;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800178 }
179
180 ret = WriteString(fd, string("Content-Length: ") + Itoa(content_length) +
181 EOL EOL);
182 if (ret < 0)
183 return -1;
184 written += ret;
185
186 return written;
187}
188
189// Writes a predetermined payload of lines of ascending bytes to a file. The
190// first byte of output is appropriately offset with respect to the request line
191// length. Returns the number of successfully written bytes.
192size_t WritePayload(int fd, const off_t start_offset, const off_t end_offset,
193 const char first_byte, const size_t line_len) {
194 CHECK_LE(start_offset, end_offset);
195 CHECK_GT(line_len, 0);
196
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800197 LOG(INFO) << "writing payload: " << line_len << "-byte lines starting with `"
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800198 << first_byte << "', offset range " << start_offset << " -> "
199 << end_offset;
200
201 // Populate line of ascending characters.
202 string line;
203 line.reserve(line_len);
204 char byte = first_byte;
205 size_t i;
206 for (i = 0; i < line_len; i++)
207 line += byte++;
208
209 const size_t total_len = end_offset - start_offset;
210 size_t remaining_len = total_len;
211 bool success = true;
212
213 // If start offset is not aligned with line boundary, output partial line up
214 // to the first line boundary.
215 size_t start_modulo = start_offset % line_len;
216 if (start_modulo) {
217 string partial = line.substr(start_modulo, remaining_len);
218 ssize_t ret = WriteString(fd, partial);
219 if ((success = (ret >= 0 && (size_t) ret == partial.length())))
220 remaining_len -= partial.length();
221 }
222
223 // Output full lines up to the maximal line boundary below the end offset.
224 while (success && remaining_len >= line_len) {
225 ssize_t ret = WriteString(fd, line);
226 if ((success = (ret >= 0 && (size_t) ret == line_len)))
227 remaining_len -= line_len;
228 }
229
230 // Output a partial line up to the end offset.
231 if (success && remaining_len) {
232 string partial = line.substr(0, remaining_len);
233 ssize_t ret = WriteString(fd, partial);
234 if ((success = (ret >= 0 && (size_t) ret == partial.length())))
235 remaining_len -= partial.length();
236 }
237
238 return (total_len - remaining_len);
239}
240
241// Write default payload lines of the form 'abcdefghij'.
242inline size_t WritePayload(int fd, const off_t start_offset,
243 const off_t end_offset) {
244 return WritePayload(fd, start_offset, end_offset, 'a', 10);
245}
246
247// Send an empty response, then kill the server.
248void HandleQuit(int fd) {
249 WriteHeaders(fd, 0, 0, kHttpResponseOk);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000250 exit(0);
251}
252
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800253
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800254// Generates an HTTP response with payload corresponding to requested offsets
255// and length. Optionally, truncate the payload at a given length and add a
256// pause midway through the transfer. Returns the total number of bytes
257// delivered or -1 for error.
258ssize_t HandleGet(int fd, const HttpRequest& request, const size_t total_length,
259 const size_t truncate_length, const int sleep_every,
260 const int sleep_secs) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800261 ssize_t ret;
262 size_t written = 0;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000263
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800264 // Obtain start offset, make sure it is within total payload length.
265 const size_t start_offset = request.start_offset;
266 if (start_offset >= total_length) {
267 LOG(WARNING) << "start offset (" << start_offset
268 << ") exceeds total length (" << total_length
269 << "), generating error response ("
270 << kHttpResponseReqRangeNotSat << ")";
271 return WriteHeaders(fd, total_length, total_length,
272 kHttpResponseReqRangeNotSat);
273 }
274
275 // Obtain end offset, adjust to fit in total payload length and ensure it does
276 // not preceded the start offset.
277 size_t end_offset = (request.end_offset > 0 ?
278 request.end_offset : total_length);
279 if (end_offset < start_offset) {
280 LOG(WARNING) << "end offset (" << end_offset << ") precedes start offset ("
281 << start_offset << "), generating error response";
282 return WriteHeaders(fd, 0, 0, kHttpResponseBadRequest);
283 }
284 if (end_offset > total_length) {
285 LOG(INFO) << "requested end offset (" << end_offset
286 << ") exceeds total length (" << total_length << "), adjusting";
287 end_offset = total_length;
288 }
289
290 // Generate headers
291 LOG(INFO) << "generating response header: range=" << start_offset << "-"
292 << (end_offset - 1) << "/" << (end_offset - start_offset)
293 << ", return code=" << request.return_code;
294 if ((ret = WriteHeaders(fd, start_offset, end_offset,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800295 request.return_code)) < 0)
296 return -1;
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800297 LOG(INFO) << ret << " header bytes written";
298 written += ret;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800299
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800300 // Compute payload length, truncate as necessary.
301 size_t payload_length = end_offset - start_offset;
302 if (truncate_length > 0 && truncate_length < payload_length) {
303 LOG(INFO) << "truncating request payload length (" << payload_length
304 << ") at " << truncate_length;
305 payload_length = truncate_length;
306 end_offset = start_offset + payload_length;
307 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800308
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800309 LOG(INFO) << "generating response payload: range=" << start_offset << "-"
310 << (end_offset - 1) << "/" << (end_offset - start_offset);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800311
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800312 // Decide about optional midway delay.
313 if (truncate_length > 0 && sleep_every > 0 && sleep_secs >= 0 &&
314 start_offset % (truncate_length * sleep_every) == 0) {
315 const off_t midway_offset = start_offset + payload_length / 2;
316
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800317 if ((ret = WritePayload(fd, start_offset, midway_offset)) < 0)
318 return -1;
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800319 LOG(INFO) << ret << " payload bytes written (first chunk)";
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800320 written += ret;
321
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800322 LOG(INFO) << "sleeping for " << sleep_secs << " seconds...";
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800323 sleep(sleep_secs);
324
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800325 if ((ret = WritePayload(fd, midway_offset, end_offset)) < 0)
326 return -1;
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800327 LOG(INFO) << ret << " payload bytes written (second chunk)";
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800328 written += ret;
329 } else {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800330 if ((ret = WritePayload(fd, start_offset, end_offset)) < 0)
331 return -1;
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800332 LOG(INFO) << ret << " payload bytes written";
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800333 written += ret;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000334 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800335
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800336 LOG(INFO) << "response generation complete, " << written
337 << " total bytes written";
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800338 return written;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000339}
340
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800341ssize_t HandleGet(int fd, const HttpRequest& request,
342 const size_t total_length) {
343 return HandleGet(fd, request, total_length, 0, 0, 0);
344}
345
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700346// Handles /redirect/<code>/<url> requests by returning the specified
347// redirect <code> with a location pointing to /<url>.
348void HandleRedirect(int fd, const HttpRequest& request) {
349 LOG(INFO) << "Redirecting...";
350 string url = request.url;
351 CHECK_EQ(0, url.find("/redirect/"));
352 url.erase(0, strlen("/redirect/"));
353 string::size_type url_start = url.find('/');
354 CHECK_NE(url_start, string::npos);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800355 HttpResponseCode code = StringToHttpResponseCode(url.c_str());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700356 url.erase(0, url_start);
357 url = "http://" + request.host + url;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800358 const char *status = GetHttpResponseDescription(code);
359 if (!status)
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700360 CHECK(false) << "Unrecognized redirection code: " << code;
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700361 LOG(INFO) << "Code: " << code << " " << status;
362 LOG(INFO) << "New URL: " << url;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800363
364 ssize_t ret;
365 if ((ret = WriteString(fd, "HTTP/1.1 " + Itoa(code) + " " +
366 status + EOL)) < 0)
367 return;
368 WriteString(fd, "Location: " + url + EOL);
369}
370
371// Generate a page not found error response with actual text payload. Return
372// number of bytes written or -1 for error.
373ssize_t HandleError(int fd, const HttpRequest& request) {
374 LOG(INFO) << "Generating error HTTP response";
375
376 ssize_t ret;
377 size_t written = 0;
378
379 const string data("This is an error page.");
380
381 if ((ret = WriteHeaders(fd, 0, data.size(), kHttpResponseNotFound)) < 0)
382 return -1;
383 written += ret;
384
385 if ((ret = WriteString(fd, data)) < 0)
386 return -1;
387 written += ret;
388
389 return written;
390}
391
392// Generate an error response if the requested offset is nonzero, up to a given
393// maximal number of successive failures. The error generated is an "Internal
394// Server Error" (500).
395ssize_t HandleErrorIfOffset(int fd, const HttpRequest& request,
396 size_t end_offset, int max_fails) {
397 static int num_fails = 0;
398
399 if (request.start_offset > 0 && num_fails < max_fails) {
400 LOG(INFO) << "Generating error HTTP response";
401
402 ssize_t ret;
403 size_t written = 0;
404
405 const string data("This is an error page.");
406
407 if ((ret = WriteHeaders(fd, 0, data.size(),
408 kHttpResponseInternalServerError)) < 0)
409 return -1;
410 written += ret;
411
412 if ((ret = WriteString(fd, data)) < 0)
413 return -1;
414 written += ret;
415
416 num_fails++;
417 return written;
418 } else {
419 num_fails = 0;
420 return HandleGet(fd, request, end_offset);
421 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700422}
423
adlr@google.com3defe6a2009-12-04 20:57:17 +0000424void HandleDefault(int fd, const HttpRequest& request) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800425 const off_t start_offset = request.start_offset;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000426 const string data("unhandled path");
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800427 const size_t size = data.size();
428 ssize_t ret;
429
430 if ((ret = WriteHeaders(fd, start_offset, size, request.return_code)) < 0)
431 return;
432 WriteString(fd, (start_offset < static_cast<off_t>(size) ?
433 data.substr(start_offset) : ""));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000434}
435
Gilad Arnold48085ba2011-11-16 09:36:08 -0800436
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800437// Break a URL into terms delimited by slashes.
438class UrlTerms {
439 public:
440 UrlTerms(string &url, size_t num_terms) {
441 // URL must be non-empty and start with a slash.
442 CHECK_GT(url.size(), 0);
443 CHECK_EQ(url[0], '/');
444
445 // Split it into terms delimited by slashes, omitting the preceeding slash.
446 base::SplitStringDontTrim(url.substr(1), '/', &terms);
447
448 // Ensure expected length.
449 CHECK_EQ(terms.size(), num_terms);
450 }
451
452 inline string Get(const off_t index) const {
453 return terms[index];
454 }
455 inline const char *GetCStr(const off_t index) const {
456 return Get(index).c_str();
457 }
458 inline int GetInt(const off_t index) const {
459 return atoi(GetCStr(index));
460 }
461 inline long GetLong(const off_t index) const {
462 return atol(GetCStr(index));
463 }
464
465 private:
466 std::vector<string> terms;
467};
Gilad Arnold48085ba2011-11-16 09:36:08 -0800468
adlr@google.com3defe6a2009-12-04 20:57:17 +0000469void HandleConnection(int fd) {
470 HttpRequest request;
471 ParseRequest(fd, &request);
472
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800473 string &url = request.url;
474 if (url == "/quitquitquit") {
475 HandleQuit(fd);
476 } else if (StartsWithASCII(url, "/download/", true)) {
477 const UrlTerms terms(url, 2);
478 HandleGet(fd, request, terms.GetLong(1));
479 } else if (StartsWithASCII(url, "/flaky/", true)) {
480 const UrlTerms terms(url, 5);
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800481 HandleGet(fd, request, terms.GetLong(1), terms.GetLong(2), terms.GetLong(3),
482 terms.GetLong(4));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800483 } else if (url.find("/redirect/") == 0) {
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700484 HandleRedirect(fd, request);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800485 } else if (url == "/error") {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800486 HandleError(fd, request);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800487 } else if (StartsWithASCII(url, "/error-if-offset/", true)) {
488 const UrlTerms terms(url, 3);
489 HandleErrorIfOffset(fd, request, terms.GetLong(1), terms.GetInt(2));
490 } else {
adlr@google.com3defe6a2009-12-04 20:57:17 +0000491 HandleDefault(fd, request);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800492 }
adlr@google.com3defe6a2009-12-04 20:57:17 +0000493
494 close(fd);
495}
496
497} // namespace chromeos_update_engine
498
499using namespace chromeos_update_engine;
500
501int main(int argc, char** argv) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700502 // Ignore SIGPIPE on write() to sockets.
503 signal(SIGPIPE, SIG_IGN);
Darin Petkovf67bb1f2010-11-08 16:10:26 -0800504
adlr@google.com3defe6a2009-12-04 20:57:17 +0000505 socklen_t clilen;
506 struct sockaddr_in server_addr;
507 struct sockaddr_in client_addr;
508 memset(&server_addr, 0, sizeof(server_addr));
509 memset(&client_addr, 0, sizeof(client_addr));
510
511 int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
512 if (listen_fd < 0)
513 LOG(FATAL) << "socket() failed";
514
515 server_addr.sin_family = AF_INET;
516 server_addr.sin_addr.s_addr = INADDR_ANY;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800517 server_addr.sin_port = htons(kServerPort);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000518
519 {
520 // Get rid of "Address in use" error
521 int tr = 1;
522 if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &tr,
523 sizeof(int)) == -1) {
524 perror("setsockopt");
525 exit(1);
526 }
527 }
528
529 if (bind(listen_fd, reinterpret_cast<struct sockaddr *>(&server_addr),
530 sizeof(server_addr)) < 0) {
531 perror("bind");
532 exit(1);
533 }
534 CHECK_EQ(listen(listen_fd,5), 0);
535 while (1) {
536 clilen = sizeof(client_addr);
537 int client_fd = accept(listen_fd,
538 (struct sockaddr *) &client_addr,
539 &clilen);
540 LOG(INFO) << "got past accept";
541 if (client_fd < 0)
542 LOG(FATAL) << "ERROR on accept";
543 HandleConnection(client_fd);
544 }
545 return 0;
546}