├── start_build.sh
├── www
└── index.html
├── .gitignore
├── CMakeLists.txt
├── README.md
├── LICENSE
├── deps
└── lwlog
│ └── lwlog.h
└── webserver.c
/start_build.sh:
--------------------------------------------------------------------------------
1 | #/bin/sh
2 |
3 | if test -d build ;
4 | then rm -rf build
5 | fi
6 | mkdir build
7 |
8 | cd build
9 | cmake ..
10 | #cmake .. && make
--------------------------------------------------------------------------------
/www/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Libuv Webserver
5 |
6 |
7 |
8 |
9 | This is a lightweight http server based on libuv and http-parser.
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Object files
2 | *.o
3 | *.ko
4 | *.obj
5 | *.elf
6 |
7 | # Precompiled Headers
8 | *.gch
9 | *.pch
10 |
11 | # Libraries
12 | *.lib
13 | *.a
14 | *.la
15 | *.lo
16 |
17 | # Shared objects (inc. Windows DLLs)
18 | *.dll
19 | *.so
20 | *.so.*
21 | *.dylib
22 |
23 | # Executables
24 | *.exe
25 | *.out
26 | *.app
27 | *.i*86
28 | *.x86_64
29 | *.hex
30 | /build
31 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.4)
2 |
3 | project(libuv_webserver)
4 |
5 | set(SOURCE_FILES webserver.c)
6 |
7 | include_directories(${PROJECT_SOURCE_DIR}/deps "/usr/local/include")
8 |
9 | link_directories("/usr/local/lib" "${PROJECT_SOURCE_DIR}/deps/http-parser")
10 |
11 | add_executable(libuv_webserver ${SOURCE_FILES})
12 |
13 | target_link_libraries(libuv_webserver "libuv.a" "libhttp_parser.a")
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | libuv-webserver
2 | ===============
3 |
4 | A lightweight webserver based on libuv and http-parser
5 |
6 | ## Programming Live Video
7 | * [Ryan Dahl's tutorial](http://vimeo.com/24713213)
8 |
9 | ## Good http serve on libuv
10 | *
11 | *
12 |
13 | ## Build & Run
14 | * `./start_build.sh`
15 | * `cd build`
16 | * `make`
17 | * `./libuv_webserver`
18 | * `curl http://127.0.0.1:8000/`
19 |
20 | ## Stress test
21 | * `ab -n 5000 -c 500 http://127.0.0.1:8000/`
22 |
23 | ## TODO
24 | * split code into tcp and http part
25 | * http part will transform between structs and http-parser output
26 | * check memory leaks on libuv part.
27 | * build a http response part for easy responses.
28 | *
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Bob Liu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/deps/lwlog/lwlog.h:
--------------------------------------------------------------------------------
1 | /*
2 | * @file lwlog.h
3 | * @auther Akagi201
4 | *
5 | * @date 2014/11/30
6 | */
7 |
8 | #ifndef LWLOG_H_
9 | #define LWLOG_H_ (1)
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #ifndef LOG_LEVEL
16 | #define LOG_LEVEL (7)
17 | #endif
18 |
19 | #ifndef LOG_COLOR
20 | #define LOG_COLOR (1)
21 | #endif
22 |
23 | // log levels the same as syslog
24 | #define EMERG (0)
25 | #define ALERT (1)
26 | #define CRIT (2)
27 | #define ERR (3)
28 | #define WARNING (4)
29 | #define NOTICE (5)
30 | #define INFO (6)
31 | #define DEBUG (7)
32 |
33 | // colors
34 | #define NONE "\e[0m"
35 | #define BLACK "\e[0;30m"
36 | #define L_BLACK "\e[1;30m"
37 | #define RED "\e[0;31m"
38 | #define L_RED "\e[1;31m"
39 | #define GREEN "\e[0;32m"
40 | #define L_GREEN "\e[1;32m"
41 | #define BROWN "\e[0;33m"
42 | #define YELLOW "\e[1;33m"
43 | #define BLUE "\e[0;34m"
44 | #define L_BLUE "\e[1;34m"
45 | #define PURPLE "\e[0;35m"
46 | #define L_PURPLE "\e[1;35m"
47 | #define CYAN "\e[0;36m"
48 | #define L_CYAN "\e[1;36m"
49 | #define GRAY "\e[0;37m"
50 | #define WHITE "\e[1;37m"
51 |
52 | #define BOLD "\e[1m"
53 | #define UNDERLINE "\e[4m"
54 | #define BLINK "\e[5m"
55 | #define REVERSE "\e[7m"
56 | #define HIDE "\e[8m"
57 | #define CLEAR "\e[2J"
58 | #define CLRLINE "\r\e[K" //or "\e[1K\r"
59 |
60 | #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
61 |
62 | /* safe readable version of errno */
63 | #define clean_errno() (errno == 0 ? "None" : strerror(errno))
64 |
65 | #define lwlog_emerg(M, ...) fprintf(stderr, RED "[EMERG] " "%s (%s:%d) " NONE M YELLOW " errno: %s\n" NONE, __func__, __FILE__, __LINE__, ##__VA_ARGS__, clean_errno());
66 | #define lwlog_alert(M, ...) fprintf(stderr, PURPLE "[ALERT] " "%s (%s:%d) " NONE M YELLOW " errno: %s\n" NONE, __func__, __FILE__, __LINE__, ##__VA_ARGS__, clean_errno());
67 | #define lwlog_crit(M, ...) fprintf(stderr, YELLOW "[CRIT] " "%s (%s:%d) " NONE M YELLOW " errno: %s\n" NONE, __func__, __FILE__, __LINE__, ##__VA_ARGS__, clean_errno());
68 | #define lwlog_err(M, ...) fprintf(stderr, BROWN "[ERR] " "%s (%s:%d) " NONE M YELLOW " errno: %s\n" NONE, __func__, __FILE__, __LINE__, ##__VA_ARGS__, clean_errno());
69 | #define lwlog_warning(M, ...) fprintf(stderr, BLUE "[WARNING] " "%s (%s:%d) " NONE M YELLOW " errno: %s\n" NONE, __func__, __FILE__, __LINE__, ##__VA_ARGS__, clean_errno());
70 | #define lwlog_notice(M, ...) fprintf(stderr, CYAN "[NOTICE] " "%s (%s:%d) " NONE M YELLOW " errno: %s\n" NONE, __func__, __FILE__, __LINE__, ##__VA_ARGS__, clean_errno());
71 | #define lwlog_info(M, ...) fprintf(stderr, GREEN "[INFO] " "%s (%s:%d) " NONE M "\n", __func__, __FILE__, __LINE__, ##__VA_ARGS__);
72 | #define lwlog_debug(M, ...) fprintf(stderr, GRAY "[DEBUG] " "%s (%s:%d) " NONE M "\n", __func__, __FILE__, __LINE__, ##__VA_ARGS__);
73 |
74 | /* LOG_LEVEL controls */
75 | #if LOG_LEVEL < DEBUG
76 | #undef lwlog_debug
77 | #define lwlog_debug(M, ...) do{}while(0)
78 | #endif
79 |
80 | #if LOG_LEVEL < INFO
81 | #undef lwlog_info
82 | #define lwlog_info(M, ...) do{}while(0)
83 | #endif
84 |
85 | #if LOG_LEVEL < NOTICE
86 | #undef lwlog_notice
87 | #define lwlog_notice(M, ...) do{}while(0)
88 | #endif
89 |
90 | #if LOG_LEVEL < WARNING
91 | #undef lwlog_warning
92 | #define lwlog_warning(M, ...) do{}while(0)
93 | #endif
94 |
95 | #if LOG_LEVEL < ERR
96 | #undef lwlog_err
97 | #define lwlog_err(M, ...) do{}while(0)
98 | #endif
99 |
100 | #if LOG_LEVEL < CRIT
101 | #undef lwlog_crit
102 | #define lwlog_crit(M, ...) do{}while(0)
103 | #endif
104 |
105 | #if LOG_LEVEL < ALERT
106 | #undef lwlog_alert
107 | #define lwlog_alert(M, ...) do{}while(0)
108 | #endif
109 |
110 | #if LOG_LEVEL < EMERG
111 | #undef lwlog_emerg
112 | #define lwlog_emerg(M, ...) do{}while(0)
113 | #endif
114 |
115 | /* LOG_COLOR controls */
116 | #if LOG_COLOR < 1
117 |
118 | #undef NONE
119 | #define NONE
120 |
121 | #undef RED
122 | #define RED
123 |
124 | #undef PURPLE
125 | #define PURPLE
126 |
127 | #undef YELLOW
128 | #define YELLOW
129 |
130 | #undef BROWN
131 | #define BROWN
132 |
133 | #undef GREEN
134 | #define GREEN
135 |
136 | #undef CYAN
137 | #define CYAN
138 |
139 | #undef BLUE
140 | #define BLUE
141 |
142 | #undef GRAY
143 | #define GRAY
144 |
145 | #endif
146 |
147 | #endif // LWLOG_H_
148 |
--------------------------------------------------------------------------------
/webserver.c:
--------------------------------------------------------------------------------
1 | /*
2 | * @file webserver.c
3 | * @author Akagi201
4 | * @date 2015/01/03
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include // _SC_NPROCESSORS_ONLN on OS X
12 | #include "uv.h"
13 | #include "http-parser/http_parser.h"
14 | #include "lwlog/lwlog.h"
15 |
16 | #define HTTP_PORT (8000)
17 | #define MAX_WRITE_HANDLES (1000)
18 | #define INDEX_HTML "../www/index.html"
19 |
20 | #define HTTP_HEADER "HTTP/1.1 200 OK\r\n" \
21 | "Content-Type: text/html\r\n" \
22 | "\r\n"
23 |
24 | #define MAX_HTTP_HEADERS (20)
25 |
26 | #define UV_ERR(err, msg) lwlog_err("%s: [%s(%d): %s]\n", msg, uv_err_name((err)), (int)err, uv_strerror((err)))
27 |
28 | #define UV_CHECK(err, msg) \
29 | do { \
30 | if (err != 0) { \
31 | UV_ERR(err, msg); \
32 | exit(1); \
33 | } \
34 | } while(0)
35 |
36 | /**
37 | * Represents a single http header.
38 | */
39 | typedef struct {
40 | char *field;
41 | char *value;
42 | size_t field_length;
43 | size_t value_length;
44 | } http_header_t;
45 |
46 | /**
47 | * Represents a http request with internal dependencies.
48 | *
49 | * - write request for sending the response
50 | * - reference to tcp socket as write stream
51 | * - instance of http_parser parser
52 | * - string of the http url
53 | * - string of the http method
54 | * - amount of total header lines
55 | * - http header array
56 | * - body content
57 | */
58 | typedef struct {
59 | uv_write_t req;
60 | uv_stream_t stream;
61 | http_parser parser;
62 | char *url;
63 | char *method;
64 | int header_lines;
65 | http_header_t headers[MAX_HTTP_HEADERS];
66 | char *body;
67 | size_t body_length;
68 | uv_buf_t resp_buf[2];
69 | } http_request_t;
70 |
71 | static uv_loop_t *uv_loop;
72 | static uv_tcp_t server;
73 | static http_parser_settings parser_settings;
74 |
75 | void on_close(uv_handle_t *handle) {
76 |
77 | http_request_t *http_request = (http_request_t *) handle->data;
78 |
79 | lwlog_info("connection closed");
80 |
81 | if (NULL != http_request) {
82 | free(http_request);
83 | http_request = NULL;
84 | }
85 |
86 | return;
87 | }
88 |
89 | void alloc_cb(uv_handle_t *handle/*handle*/, size_t suggested_size, uv_buf_t *buf) {
90 | *buf = uv_buf_init((char *) malloc(suggested_size), (unsigned int)suggested_size);
91 |
92 | return;
93 | }
94 |
95 | void on_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
96 | ssize_t parsed = 0;
97 | lwlog_info("on read, nread: %ld", nread);
98 |
99 | /* get back our http request*/
100 | http_request_t *http_request = stream->data;
101 |
102 | if (nread >= 0) {
103 | /* call our http parser on the received tcp payload */
104 | parsed = (ssize_t) http_parser_execute(
105 | &http_request->parser, &parser_settings, buf->base, (size_t)nread);
106 | if (parsed < nread) {
107 | lwlog_err("parse error");
108 | uv_close((uv_handle_t *) &http_request->stream, on_close);
109 | }
110 | } else {
111 | if (nread != UV_EOF) {
112 | UV_ERR(nread, "Read error");
113 | }
114 | uv_close((uv_handle_t *) &http_request->stream, on_close);
115 | }
116 |
117 | if (NULL != buf->base) {
118 | free(buf->base);
119 | }
120 |
121 | return;
122 | }
123 |
124 | /**
125 | * Initializes default values, counters.
126 | */
127 | int on_message_begin(http_parser *parser/*parser*/) {
128 | lwlog_info("***MESSAGE BEGIN***");
129 | http_request_t *http_request = parser->data;
130 | http_request->header_lines = 0;
131 |
132 | return 0;
133 | }
134 |
135 | /**
136 | * Extract the method name.
137 | */
138 | int on_headers_complete(http_parser *parser/*parser*/) {
139 | lwlog_info("***HEADERS COMPLETE***");
140 |
141 | http_request_t *http_request = parser->data;
142 |
143 | const char *method = http_method_str((enum http_method)parser->method);
144 |
145 | http_request->method = malloc(sizeof(method));
146 | strncpy(http_request->method, method, strlen(method));
147 |
148 | return 0;
149 | }
150 |
151 | /**
152 | * Copies url string to http_request->url.
153 | */
154 | int on_url(http_parser *parser/*parser*/, const char *at, size_t length) {
155 | lwlog_info("Url: %.*s", (int) length, at);
156 |
157 | http_request_t *http_request = parser->data;
158 |
159 | http_request->url = malloc(length + 1);
160 |
161 | strncpy(http_request->url, at, length);
162 |
163 | http_request->url[length] = '\0';
164 |
165 | return 0;
166 | }
167 |
168 | /**
169 | * Copy the header field name to the current header item.
170 | */
171 | int on_header_field(http_parser *parser/*parser*/, const char *at, size_t length) {
172 | lwlog_info("Header field: %.*s", (int) length, at);
173 |
174 | http_request_t *http_request = parser->data;
175 |
176 | http_header_t *header = &http_request->headers[http_request->header_lines];
177 |
178 | header->field = malloc(length + 1);
179 | header->field_length = length;
180 |
181 | strncpy(header->field, at, length);
182 |
183 | header->field[length] = '\0';
184 |
185 | return 0;
186 | }
187 |
188 | /**
189 | * Now copy its assigned value.
190 | */
191 | int on_header_value(http_parser *parser/*parser*/, const char *at, size_t length) {
192 | lwlog_info("Header value: %.*s", (int) length, at);
193 |
194 | http_request_t *http_request = parser->data;
195 |
196 | http_header_t *header = &http_request->headers[http_request->header_lines];
197 |
198 | header->value = malloc(length + 1);
199 | header->value_length = length;
200 |
201 | strncpy(header->value, at, length);
202 |
203 | header->value[length] = '\0';
204 |
205 | ++http_request->header_lines;
206 |
207 | return 0;
208 | }
209 |
210 | int on_body(http_parser *parser/*parser*/, const char *at, size_t length) {
211 | lwlog_info("Body: %.*s", (int) length, at);
212 | http_request_t *http_request = parser->data;
213 |
214 | http_request->body = malloc(length + 1);
215 | http_request->body_length = length;
216 |
217 | strncpy(http_request->body, at, length);
218 |
219 | http_request->body[length] = '\0';
220 |
221 | return 0;
222 | }
223 |
224 | /**
225 | * Closes current tcp socket after write.
226 | */
227 | void on_put_write(uv_write_t *req, int status) {
228 | int i = 0;
229 | http_header_t *header = NULL;
230 | http_request_t *http_request = req->data;
231 |
232 | UV_CHECK(status, "on_put_write");
233 |
234 | if (http_request->url != NULL) {
235 | free(http_request->url);
236 | http_request->url = NULL;
237 | }
238 |
239 | if (http_request->body != NULL) {
240 | free(http_request->body);
241 | http_request->body = NULL;
242 | }
243 |
244 | if (http_request->method != NULL) {
245 | free(http_request->method);
246 | http_request->method = NULL;
247 | }
248 |
249 | for (i = 0; i < http_request->header_lines; ++i) {
250 | header = &http_request->headers[i];
251 | if (header->field != NULL) {
252 | free(header->field);
253 | header->field = NULL;
254 | }
255 | if (header->value != NULL) {
256 | free(header->value);
257 | header->value = NULL;
258 | }
259 | }
260 |
261 | if (!uv_is_closing((uv_handle_t*)req->handle)) {
262 | uv_close((uv_handle_t *) req->handle, on_close);
263 | }
264 |
265 | return;
266 | }
267 |
268 | /**
269 | * Closes current tcp socket after write.
270 | */
271 | void on_get_write(uv_write_t *req, int status){
272 | int i = 0;
273 | http_header_t *header = NULL;
274 | http_request_t *http_request = req->data;
275 | UV_CHECK(status, "on_get_write");
276 |
277 | if (http_request->url != NULL) {
278 | free(http_request->url);
279 | http_request->url = NULL;
280 | }
281 |
282 | if (http_request->method != NULL) {
283 | free(http_request->method);
284 | http_request->method = NULL;
285 | }
286 |
287 | for (i = 0; i < http_request->header_lines; ++i) {
288 | header = &http_request->headers[i];
289 | if (header->field != NULL) {
290 | free(header->field);
291 | header->field = NULL;
292 | }
293 | if (header->value != NULL) {
294 | free(header->value);
295 | header->value = NULL;
296 | }
297 | }
298 |
299 | if (!uv_is_closing((uv_handle_t*)req->handle)) {
300 | uv_close((uv_handle_t *) req->handle, on_close);
301 | }
302 |
303 | return;
304 | }
305 |
306 | void on_html_write(uv_write_t *req, int status) {
307 | char *buf = NULL;
308 | int i = 0;
309 | http_header_t *header = NULL;
310 | http_request_t *http_request = req->data;
311 | buf = http_request->resp_buf[1].base;
312 |
313 | UV_CHECK(status, "on_html_write");
314 |
315 | if (NULL != buf) {
316 | free(buf);
317 | buf = NULL;
318 | }
319 |
320 | if (http_request->url != NULL) {
321 | free(http_request->url);
322 | http_request->url = NULL;
323 | }
324 |
325 | if (http_request->method != NULL) {
326 | free(http_request->method);
327 | http_request->method = NULL;
328 | }
329 |
330 | for (i = 0; i < http_request->header_lines; ++i) {
331 | header = &http_request->headers[i];
332 | if (header->field != NULL) {
333 | free(header->field);
334 | header->field = NULL;
335 | }
336 | if (header->value != NULL) {
337 | free(header->value);
338 | header->value = NULL;
339 | }
340 | }
341 |
342 | if (!uv_is_closing((uv_handle_t*)req->handle)) {
343 | uv_close((uv_handle_t *) req->handle, on_close);
344 | }
345 |
346 | return;
347 | }
348 |
349 | int on_message_complete(http_parser *parser) {
350 | int i = 0;
351 | http_header_t *header = NULL;
352 |
353 | lwlog_info("***MESSAGE COMPLETE***");
354 |
355 | http_request_t *http_request = parser->data;
356 |
357 | /* now print the ordered http http_request to console */
358 | printf("url: %s\n", http_request->url);
359 | printf("method: %s\n", http_request->method);
360 | for (i = 0; i < 5; ++i) {
361 | header = &http_request->headers[i];
362 | if (header->field) {
363 | printf("Header: %s: %s\n", header->field, header->value);
364 | }
365 | }
366 | printf("body: %s\n", http_request->body);
367 | printf("\n");
368 |
369 | if (0 == strcmp(http_request->url, "/")) {
370 | lwlog_info("root");
371 | char *file_contents;
372 | long input_file_size;
373 |
374 | // send http response header
375 | http_request->resp_buf[0].base = HTTP_HEADER;
376 | http_request->resp_buf[0].len = sizeof(HTTP_HEADER) - 1;
377 |
378 | // send http response body
379 | FILE *input_file = fopen(INDEX_HTML, "rb");
380 | fseek(input_file, 0, SEEK_END);
381 | input_file_size = ftell(input_file);
382 | rewind(input_file);
383 | file_contents = malloc(input_file_size * (sizeof(char)));
384 | fread(file_contents, sizeof(char), (size_t)input_file_size, input_file);
385 | fclose(input_file);
386 |
387 | lwlog_info("input_file_size: %ld", input_file_size);
388 |
389 | http_request->resp_buf[1].base = file_contents;
390 | http_request->resp_buf[1].len = (size_t)input_file_size;
391 |
392 | /* lets send our short http hello world response and close the socket */
393 | uv_write(&http_request->req, &http_request->stream, http_request->resp_buf, 2, on_html_write);
394 | } else if (0 == strcmp(http_request->url, "/favicon.ico")) {
395 | lwlog_info("favicon");
396 | http_request->resp_buf[0].base = HTTP_HEADER;
397 | http_request->resp_buf[0].len = sizeof(HTTP_HEADER) - 1;
398 | /* lets send our short http hello world response and close the socket */
399 | uv_write(&http_request->req, &http_request->stream, http_request->resp_buf, 1, on_get_write);
400 | } else {
401 | lwlog_err("undefined url: %s", http_request->url);
402 | http_request->resp_buf[0].base = HTTP_HEADER;
403 | http_request->resp_buf[0].len = sizeof(HTTP_HEADER) - 1;
404 | /* lets send our short http hello world response and close the socket */
405 | uv_write(&http_request->req, &http_request->stream, http_request->resp_buf, 1, on_get_write);
406 | }
407 |
408 | return 0;
409 | }
410 |
411 | void on_connect(uv_stream_t *server_handle, int status) {
412 | int ret = 0;
413 | int i = 0;
414 | UV_CHECK(status, "connect");
415 | assert((uv_tcp_t *) server_handle == &server);
416 |
417 | /* initialize a new http http_request struct */
418 | http_request_t *http_request = malloc(sizeof(http_request_t));
419 |
420 | /* create an extra tcp handle for the http_request */
421 | uv_tcp_init(uv_loop, (uv_tcp_t *) &http_request->stream);
422 |
423 | /* set references so we can use our http_request in http_parser and libuv */
424 | http_request->stream.data = http_request;
425 | http_request->parser.data = http_request;
426 | http_request->req.data = http_request;
427 |
428 | /* accept the created http_request */
429 | ret = uv_accept(server_handle, &http_request->stream);
430 | if (0 == ret) {
431 | http_request->url = NULL;
432 | http_request->method = NULL;
433 | http_request->body = NULL;
434 | http_request->header_lines = 0;
435 | for (i = 0; i < MAX_HTTP_HEADERS; ++i) {
436 | http_request->headers[i].field = NULL;
437 | http_request->headers[i].field_length = 0;
438 | http_request->headers[i].value = NULL;
439 | http_request->headers[i].value_length = 0;
440 | }
441 | /* initialize our http parser */
442 | http_parser_init(&http_request->parser, HTTP_REQUEST);
443 | /* start reading from the tcp http_request socket */
444 | uv_read_start(&http_request->stream, alloc_cb, on_read);
445 | } else {
446 | /* we seem to have an error and quit */
447 | uv_close((uv_handle_t *) &http_request->stream, on_close);
448 | //UV_CHECK(ret, "accept");
449 | }
450 |
451 | return;
452 | }
453 |
454 | int main(int argc, char *argv[]) {
455 | long cores = 0;
456 | char cores_string[10] = {0};
457 | int ret = 0;
458 | struct sockaddr_in address;
459 |
460 | signal(SIGPIPE, SIG_IGN);
461 |
462 | cores = sysconf(_SC_NPROCESSORS_ONLN);
463 | lwlog_info("Number of available CPU cores %ld", cores);
464 | snprintf(cores_string, sizeof(cores_string), "%ld", cores);
465 | setenv("UV_THREADPOOL_SIZE", cores_string, 1);
466 |
467 | parser_settings.on_message_begin = on_message_begin;
468 | parser_settings.on_url = on_url;
469 | parser_settings.on_header_field = on_header_field;
470 | parser_settings.on_header_value = on_header_value;
471 | parser_settings.on_headers_complete = on_headers_complete;
472 | parser_settings.on_body = on_body;
473 | parser_settings.on_message_complete = on_message_complete;
474 |
475 | uv_loop = uv_default_loop();
476 |
477 | ret = uv_tcp_init(uv_loop, &server);
478 | UV_CHECK(ret, "tcp_init");
479 |
480 | //ret = uv_tcp_keepalive(&server, 1, 60);
481 | //UV_CHECK(ret, "tcp_keepalive");
482 |
483 | ret = uv_ip4_addr("0.0.0.0", HTTP_PORT, &address);
484 | UV_CHECK(ret, "ip4_addr");
485 |
486 | ret = uv_tcp_bind(&server, (const struct sockaddr *) &address, 0);
487 | UV_CHECK(ret, "tcp_bind");
488 |
489 | ret = uv_listen((uv_stream_t *) &server, MAX_WRITE_HANDLES, on_connect);
490 | UV_CHECK(ret, "uv_listen");
491 |
492 | lwlog_info("Listening on port %d", HTTP_PORT);
493 |
494 | uv_run(uv_loop, UV_RUN_DEFAULT);
495 |
496 | return 0;
497 | }
498 |
--------------------------------------------------------------------------------