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

Side by Side Diff: src/platform/update_engine/test_http_server.cc

Issue 465067: Missed new files in last commit
Patch Set: Created 11 years 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
OLDNEW
(Empty)
1 // 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
13 #include <netinet/in.h>
14 #include <sys/socket.h>
15 #include <sys/types.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <algorithm>
22 #include <string>
23 #include <vector>
24 #include "chromeos/obsolete_logging.h"
25
26 using std::min;
27 using std::string;
28 using std::vector;
29
30 namespace chromeos_update_engine {
31
32 struct HttpRequest {
33 string url;
34 off_t offset;
35 };
36
37 namespace {
38 const int kPort = 8080; // hardcoded to 8080 for now
39 const int kBigLength = 100000;
40 }
41
42 bool ParseRequest(int fd, HttpRequest* request) {
43 string headers;
44 while(headers.find("\r\n\r\n") == string::npos) {
45 vector<char> buf(1024);
46 memset(&buf[0], 0, buf.size());
47 ssize_t r = read(fd, &buf[0], buf.size() - 1);
48 if (r < 0) {
49 perror("read");
50 exit(1);
51 }
52 buf.resize(r);
53
54 headers.insert(headers.end(), buf.begin(), buf.end());
55 }
56 LOG(INFO) << "got headers: " << headers;
57
58 string::size_type url_start, url_end;
59 CHECK_NE(headers.find("GET "), string::npos);
60 url_start = headers.find("GET ") + strlen("GET ");
61 url_end = headers.find(' ', url_start);
62 CHECK_NE(string::npos, url_end);
63 string url = headers.substr(url_start, url_end - url_start);
64 LOG(INFO) << "URL: " << url;
65
66 string::size_type range_start, range_end;
67 if (headers.find("\r\nRange: ") == string::npos) {
68 request->offset = 0;
69 } else {
70 range_start = headers.find("\r\nRange: ") + strlen("\r\nRange: ");
71 range_end = headers.find('\r', range_start);
72 CHECK_NE(string::npos, range_end);
73 string range_header = headers.substr(range_start, range_end - range_start);
74
75 LOG(INFO) << "Range: " << range_header;
76 CHECK(*range_header.rbegin() == '-');
77 request->offset = atoll(range_header.c_str() + strlen("bytes="));
78 LOG(INFO) << "Offset: " << request->offset;
79 }
80 request->url = url;
81 return true;
82 }
83
84 void WriteString(int fd, const string& str) {
85 unsigned int bytes_written = 0;
86 while (bytes_written < str.size()) {
87 ssize_t r = write(fd, str.c_str() + bytes_written,
88 str.size() - bytes_written);
89 LOG(INFO) << "write() wrote " << r << " bytes";
90 if (r < 0) {
91 perror("write");
92 return;
93 }
94 bytes_written += r;
95 }
96 LOG(INFO) << "WriteString wrote " << bytes_written << " bytes";
97 }
98
99 string Itoa(off_t num) {
100 char buf[100] = {0};
101 snprintf(buf, sizeof(buf), "%lld", num);
102 return buf;
103 }
104
105 void WriteHeaders(int fd, bool support_range, off_t full_size,
106 off_t start_offset) {
107 LOG(INFO) << "writing headers";
108 WriteString(fd, "HTTP/1.1 200 OK\r\n");
109 WriteString(fd, "Content-Type: application/octet-stream\r\n");
110 if (support_range) {
111 WriteString(fd, "Accept-Ranges: bytes\r\n");
112 WriteString(fd, string("Content-Range: bytes ") + Itoa(start_offset) +
113 "-" + Itoa(full_size - 1) + "/" + Itoa(full_size) + "\r\n");
114 }
115 off_t content_length = full_size;
116 if (support_range)
117 content_length -= start_offset;
118 WriteString(fd, string("Content-Length: ") + Itoa(content_length) + "\r\n");
119 WriteString(fd, "\r\n");
120 }
121
122 void HandleQuitQuitQuit(int fd) {
123 exit(0);
124 }
125
126 void HandleBig(int fd, const HttpRequest& request) {
127 const off_t full_length = kBigLength;
128 WriteHeaders(fd, true, full_length, request.offset);
129 const off_t content_length = full_length - request.offset;
130 int i = request.offset;
131 for (; i % 10; i++)
132 WriteString(fd, string(1, 'a' + (i % 10)));
133 CHECK_EQ(i % 10, 0);
134 for (; i < content_length; i += 10)
135 WriteString(fd, "abcdefghij");
136 CHECK_EQ(i, full_length);
137 }
138
139 // This is like /big, but it writes at most 9000 bytes. Also,
140 // half way through it sleeps for 70 seconds
141 // (technically, when (offset % (9000 * 7)) == 0).
142 void HandleFlaky(int fd, const HttpRequest& request) {
143 const off_t full_length = kBigLength;
144 WriteHeaders(fd, true, full_length, request.offset);
145 const off_t content_length = min(9000LL, full_length - request.offset);
146 const bool should_sleep = (request.offset % (9000 * 7)) == 0;
147
148 string buf;
149
150 for (int i = request.offset; i % 10; i++)
151 buf.append(1, 'a' + (i % 10));
152 while (buf.size() < content_length)
153 buf.append("abcdefghij");
154 buf.resize(content_length);
155
156 if (!should_sleep) {
157 LOG(INFO) << "writing data blob of size " << buf.size();
158 WriteString(fd, buf);
159 } else {
160 string::size_type half_way_point = buf.size() / 2;
161 LOG(INFO) << "writing small data blob of size " << half_way_point;
162 WriteString(fd, buf.substr(0, half_way_point));
163 sleep(10);
164 LOG(INFO) << "writing small data blob of size "
165 << (buf.size() - half_way_point);
166 WriteString(fd, buf.substr(half_way_point, buf.size() - half_way_point));
167 }
168 }
169
170 void HandleDefault(int fd, const HttpRequest& request) {
171 const string data("unhandled path");
172 WriteHeaders(fd, true, data.size(), request.offset);
173 const string data_to_write(data.substr(request.offset,
174 data.size() - request.offset));
175 WriteString(fd, data_to_write);
176 }
177
178 void HandleConnection(int fd) {
179 HttpRequest request;
180 ParseRequest(fd, &request);
181
182 if (request.url == "/quitquitquit")
183 HandleQuitQuitQuit(fd);
184 else if (request.url == "/big")
185 HandleBig(fd, request);
186 else if (request.url == "/flaky")
187 HandleFlaky(fd, request);
188 else
189 HandleDefault(fd, request);
190
191 close(fd);
192 }
193
194 } // namespace chromeos_update_engine
195
196 using namespace chromeos_update_engine;
197
198 int main(int argc, char** argv) {
199 socklen_t clilen;
200 struct sockaddr_in server_addr;
201 struct sockaddr_in client_addr;
202 memset(&server_addr, 0, sizeof(server_addr));
203 memset(&client_addr, 0, sizeof(client_addr));
204
205 int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
206 if (listen_fd < 0)
207 LOG(FATAL) << "socket() failed";
208
209 server_addr.sin_family = AF_INET;
210 server_addr.sin_addr.s_addr = INADDR_ANY;
211 server_addr.sin_port = htons(kPort);
212
213 {
214 // Get rid of "Address in use" error
215 int tr = 1;
216 if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &tr,
217 sizeof(int)) == -1) {
218 perror("setsockopt");
219 exit(1);
220 }
221 }
222
223 if (bind(listen_fd, reinterpret_cast<struct sockaddr *>(&server_addr),
224 sizeof(server_addr)) < 0) {
225 perror("bind");
226 exit(1);
227 }
228 CHECK_EQ(listen(listen_fd,5), 0);
229 while (1) {
230 clilen = sizeof(client_addr);
231 int client_fd = accept(listen_fd,
232 (struct sockaddr *) &client_addr,
233 &clilen);
234 LOG(INFO) << "got past accept";
235 if (client_fd < 0)
236 LOG(FATAL) << "ERROR on accept";
237 HandleConnection(client_fd);
238 }
239 return 0;
240 }
OLDNEW
« no previous file with comments | « src/platform/update_engine/subprocess_unittest.cc ('k') | src/platform/update_engine/update_metadata.proto » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698