├── README.md ├── membuf.c ├── membuf.h ├── test ├── main1.c ├── main2.c ├── main3.c └── wwwroot │ ├── Pawn_Language_Guide.pdf │ ├── coffee.jpg │ ├── copyright.html │ ├── copyright.jpg │ ├── copyright.png │ ├── happynewyear2014.html │ ├── happynewyear2014.jpg │ └── index.html ├── tinyweb1.c ├── tinyweb1.h ├── tinyweb2.c ├── tinyweb2.h ├── tinyweb3.c ├── tinyweb3.h └── win32 ├── tinyweb.dsw ├── tinyweb1.dsp ├── tinyweb2.dsp └── tinyweb3.dsp /README.md: -------------------------------------------------------------------------------- 1 | tinyweb 2 | ======= 3 | 4 | Tinyweb, a tiny web server based on libuv, by liigo, 2013/06. 5 | 6 | Tinyweb 是我用libuv开发的一个最精简的Web server服务器。分为三个版本,都是从真实项目中剥离出来的,从 v1 到 v2 到 v3,就是一个Web server从雏形到基本功能逐渐丰富的过程。 7 | 8 | tinyweb v1,是最基础的libuv的hello world,可用来学习libuv的入门用法;tinyweb v2,在v1的基础上,添加了解析HTTP GET请求(Request)提取`path_info`和`query_string`并发送回复(Respone)的功能;tinyweb v3,在v2的基础上,又添加了对静态文件的支持。 9 | 10 | 真正在项目中有实用价值的,我认为应该是从tinyweb v2开始引入的对`path_info`的响应处理:在项目中嵌入tinyweb服务器,响应特定`path_info`,或输出内部运行状态,或触发某个动作,如此一来,用户(或开发者自己)通过Web浏览器即可轻松完成与项目程序的有效沟通,至少免除了进程通讯之类的东西吧,通过特殊的`path_info`(比如`http://localhost/hibos`)给自己的程序留一个小小的后门也是轻而易举。 11 | 12 | CSDN博客文章链接: 13 | 14 | - [基于libuv的最精简Web服务器:tinyweb v1 v2 v3(C语言源码)](http://blog.csdn.net/liigo/article/details/38424417) 15 | - [tinyweb: C语言 + libuv 开发的最精简的WebServer(附源码)](http://blog.csdn.net/liigo/article/details/9149415) 16 | -------------------------------------------------------------------------------- /membuf.c: -------------------------------------------------------------------------------- 1 | #include "membuf.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // https://github.com/liigo/membuf 9 | // by Liigo. 10 | 11 | void membuf_init(membuf_t* buf, unsigned int initial_buffer_size) { 12 | memset(buf, 0, sizeof(membuf_t)); 13 | buf->data = initial_buffer_size > 0 ? (unsigned char*) malloc(initial_buffer_size) : NULL; 14 | buf->buffer_size = initial_buffer_size; 15 | buf->uses_local_buffer = 0; 16 | } 17 | 18 | void membuf_init_local(membuf_t* buf, void* local_buffer, unsigned int local_buffer_size) { 19 | memset(buf, 0, sizeof(membuf_t)); 20 | buf->data = (local_buffer && (local_buffer_size > 0)) ? local_buffer : NULL; 21 | buf->buffer_size = local_buffer_size; 22 | buf->uses_local_buffer = 1; 23 | } 24 | 25 | void membuf_init_move_from(membuf_t* buf, membuf_t* other) { 26 | if(other->uses_local_buffer) { 27 | membuf_init(buf, 0); 28 | if(other->size > 0) 29 | membuf_append_data(buf, other->data, other->size); 30 | } else { 31 | *buf = *other; 32 | } 33 | memset(other, 0, sizeof(membuf_t)); // other is hollowed now 34 | } 35 | 36 | void membuf_uninit(membuf_t* buf) { 37 | if(!buf->uses_local_buffer && buf->data) 38 | free(buf->data); 39 | memset(buf, 0, sizeof(membuf_t)); 40 | } 41 | 42 | void membuf_reserve(membuf_t* buf, unsigned int extra_size) { 43 | if(extra_size > buf->buffer_size - buf->size) { 44 | //calculate new buffer size 45 | unsigned int new_buffer_size = buf->buffer_size == 0 ? extra_size : buf->buffer_size << 1; 46 | unsigned int new_data_size = buf->size + extra_size; 47 | while(new_buffer_size < new_data_size) 48 | new_buffer_size <<= 1; 49 | 50 | // malloc/realloc new buffer 51 | if(buf->uses_local_buffer) { 52 | void* local = buf->data; 53 | buf->data = realloc(NULL, new_buffer_size); // alloc new buffer 54 | memcpy(buf->data, local, buf->size); // copy local bufer to new buffer 55 | buf->uses_local_buffer = 0; 56 | } else { 57 | buf->data = realloc(buf->data, new_buffer_size); // realloc new buffer 58 | } 59 | buf->buffer_size = new_buffer_size; 60 | } 61 | } 62 | 63 | unsigned int membuf_append_data(membuf_t* buf, void* data, unsigned int size) { 64 | assert(data && size > 0); 65 | membuf_reserve(buf, size); 66 | memmove(buf->data + buf->size, data, size); 67 | buf->size += size; 68 | return (buf->size - size); 69 | } 70 | 71 | unsigned int membuf_append_zeros(membuf_t* buf, unsigned int size) { 72 | membuf_reserve(buf, size); 73 | memset(buf->data + buf->size, 0, size); 74 | buf->size += size; 75 | return (buf->size - size); 76 | } 77 | 78 | unsigned int membuf_append_text(membuf_t* buf, const char* str, unsigned int len) { 79 | if(str && (len == (unsigned int)(-1))) 80 | len = strlen(str); 81 | return membuf_append_data(buf, (void*)str, len); 82 | } 83 | 84 | unsigned int membuf_append_text_zero(membuf_t* buf, const char* str, unsigned int len) { 85 | unsigned int offset; 86 | if(str && (len == (unsigned int)(-1))) 87 | len = strlen(str); 88 | membuf_reserve(buf, len + 1); 89 | offset = membuf_append_data(buf, (void*)str, len); 90 | membuf_append_zeros(buf, 1); 91 | return offset; 92 | } 93 | 94 | void* membuf_detach(membuf_t* buf, unsigned int* psize) { 95 | void* result = buf->data; 96 | if(psize) *psize = buf->size; 97 | if(buf->uses_local_buffer) { 98 | result = buf->size > 0 ? malloc(buf->size) : NULL; 99 | memcpy(result, buf->data, buf->size); 100 | } else { 101 | buf->buffer_size = 0; 102 | } 103 | buf->data = NULL; 104 | buf->size = 0; 105 | return result; 106 | } 107 | 108 | MEMBUF_INLINE void swap_data(membuf_t* buf1, membuf_t* buf2) { 109 | unsigned char* tmp_data = buf1->data; 110 | buf1->data = buf2->data; buf2->data = tmp_data; 111 | } 112 | 113 | MEMBUF_INLINE void swap_size(membuf_t* buf1, membuf_t* buf2) { 114 | unsigned int tmp_size = buf1->size; 115 | buf1->size = buf2->size; buf2->size = tmp_size; 116 | } 117 | 118 | MEMBUF_INLINE void swap_buffer_size(membuf_t* buf1, membuf_t* buf2) { 119 | unsigned int tmp_buffer_size = buf1->buffer_size; 120 | buf1->buffer_size = buf2->buffer_size; buf2->buffer_size = tmp_buffer_size; 121 | } 122 | -------------------------------------------------------------------------------- /membuf.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMBUF_H__ 2 | #define __MEMBUF_H__ 3 | 4 | // `membuf_t` is a growable continuous in-memory buffer. 5 | // It also support "local buffer" to use stack memory efficiently. 6 | // https://github.com/liigo/membuf 7 | // by Liigo, 2013-7-5, 2014-8-16, 2014-10-21, 2014-11-18. 8 | 9 | #include 10 | 11 | typedef struct { 12 | unsigned char* data; 13 | unsigned int size; 14 | unsigned int buffer_size; 15 | unsigned char uses_local_buffer; // local buffer, e.g. on stack 16 | } membuf_t; 17 | 18 | #ifndef MEMBUF_INIT_LOCAL 19 | #define MEMBUF_INIT_LOCAL(buf,n) membuf_t buf; unsigned char buf##n[n]; membuf_init_local(&buf, &buf##n, n); 20 | #endif 21 | 22 | void membuf_init(membuf_t* buf, unsigned int initial_buffer_size); 23 | void membuf_init_local(membuf_t* buf, void* local_buffer, unsigned int local_buffer_size); 24 | void membuf_init_move_from(membuf_t* buf, membuf_t* other); // don't use other anymore 25 | void membuf_uninit(membuf_t* buf); 26 | 27 | unsigned int membuf_append_data(membuf_t* buf, void* data, unsigned int size); 28 | unsigned int membuf_append_zeros(membuf_t* buf, unsigned int size); 29 | unsigned int membuf_append_text(membuf_t* buf, const char* str, unsigned int len); 30 | unsigned int membuf_append_text_zero(membuf_t* buf, const char* str, unsigned int len); 31 | 32 | static void* membuf_get_data(membuf_t* buf) { return (buf->size == 0 ? NULL : buf->data); } 33 | static unsigned int membuf_get_size(membuf_t* buf) { return buf->size; } 34 | static unsigned int membuf_is_empty(membuf_t* buf) { return buf->size > 0; } 35 | static void membuf_empty(membuf_t* buf) { buf->size = 0; } 36 | 37 | void membuf_reserve(membuf_t* buf, unsigned int extra_size); 38 | void* membuf_detach(membuf_t* buf, unsigned int* psize); // need free() result if not NULL 39 | 40 | #if defined(_MSC_VER) 41 | #define MEMBUF_INLINE static _inline 42 | #else 43 | #define MEMBUF_INLINE static inline 44 | #endif 45 | 46 | MEMBUF_INLINE unsigned int membuf_append_byte(membuf_t* buf, unsigned char b) { 47 | return membuf_append_data(buf, &b, sizeof(b)); 48 | } 49 | MEMBUF_INLINE unsigned int membuf_append_int(membuf_t* buf, int i) { 50 | return membuf_append_data(buf, &i, sizeof(i)); 51 | } 52 | MEMBUF_INLINE unsigned int membuf_append_uint(membuf_t* buf, unsigned int ui) { 53 | return membuf_append_data(buf, &ui, sizeof(ui)); 54 | } 55 | MEMBUF_INLINE unsigned int membuf_append_short(membuf_t* buf, short s) { 56 | return membuf_append_data(buf, &s, sizeof(s)); 57 | } 58 | MEMBUF_INLINE unsigned int membuf_append_ushort(membuf_t* buf, unsigned short us) { 59 | return membuf_append_data(buf, &us, sizeof(us)); 60 | } 61 | MEMBUF_INLINE unsigned int membuf_append_float(membuf_t* buf, float f) { 62 | return membuf_append_data(buf, &f, sizeof(f)); 63 | } 64 | MEMBUF_INLINE unsigned int membuf_append_double(membuf_t* buf, double d) { 65 | return membuf_append_data(buf, &d, sizeof(d)); 66 | } 67 | MEMBUF_INLINE unsigned int membuf_append_ptr(membuf_t* buf, void* ptr) { 68 | return membuf_append_data(buf, &ptr, sizeof(ptr)); 69 | } 70 | 71 | #endif //__MEMBUF_H__ 72 | -------------------------------------------------------------------------------- /test/main1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../tinyweb1.h" 5 | 6 | int main() 7 | { 8 | tinyweb_start(uv_default_loop(), "127.0.0.1", 8080); 9 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); 10 | } 11 | -------------------------------------------------------------------------------- /test/main2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../tinyweb2.h" 5 | 6 | int main() 7 | { 8 | tinyweb_start(uv_default_loop(), "127.0.0.1", 8080); 9 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); 10 | } 11 | -------------------------------------------------------------------------------- /test/main3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../tinyweb3.h" 5 | 6 | int main() 7 | { 8 | tinyweb_start(uv_default_loop(), "127.0.0.1", 8080, "D:\\Liigo\\github\\tinyweb\\test\\wwwroot"); 9 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); 10 | } 11 | -------------------------------------------------------------------------------- /test/wwwroot/Pawn_Language_Guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liigo/tinyweb/ca9417eff2d10708240311ac438fa25d7fd306ba/test/wwwroot/Pawn_Language_Guide.pdf -------------------------------------------------------------------------------- /test/wwwroot/coffee.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liigo/tinyweb/ca9417eff2d10708240311ac438fa25d7fd306ba/test/wwwroot/coffee.jpg -------------------------------------------------------------------------------- /test/wwwroot/copyright.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Copyright 2013-2014, by Liigo.

4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/wwwroot/copyright.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liigo/tinyweb/ca9417eff2d10708240311ac438fa25d7fd306ba/test/wwwroot/copyright.jpg -------------------------------------------------------------------------------- /test/wwwroot/copyright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liigo/tinyweb/ca9417eff2d10708240311ac438fa25d7fd306ba/test/wwwroot/copyright.png -------------------------------------------------------------------------------- /test/wwwroot/happynewyear2014.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Happy new year 2014!

4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/wwwroot/happynewyear2014.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liigo/tinyweb/ca9417eff2d10708240311ac438fa25d7fd306ba/test/wwwroot/happynewyear2014.jpg -------------------------------------------------------------------------------- /test/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Welcome to tinyweb

4 |

This is the home page, for tinyweb v3.

5 | 6 |

Link to files:

7 |

index.html

8 |

copyright.html

9 |

happynewyear2014.html

10 | 11 |

Link to actions:

12 |

/404

13 |

/user/query?author=liigo

14 |

/any/other/pathinfo?query=strings&id=123

15 | 16 |

Image:

17 |

18 | 19 |

Octet stream:

20 |

Pawn_Language_Guide.pdf

21 |

CookTime.apk (Remote link)

22 | 23 | 24 | -------------------------------------------------------------------------------- /tinyweb1.c: -------------------------------------------------------------------------------- 1 | #include "tinyweb1.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // Tinyweb v1, a tiny web server based on libuv, by liigo, 2013-6-20. 10 | 11 | uv_tcp_t _server; 12 | uv_tcp_t _client; 13 | uv_loop_t* _loop; 14 | 15 | static void tinyweb_on_connection(uv_stream_t* server, int status); 16 | 17 | //start web server, linstening ip:port 18 | //ip can be NULL or "", which means "0.0.0.0" 19 | void tinyweb_start(uv_loop_t* loop, const char* ip, int port) { 20 | struct sockaddr_in addr; 21 | uv_ip4_addr((ip && ip[0]) ? ip : "0.0.0.0", port, &addr); 22 | _loop = loop; 23 | uv_tcp_init(_loop, &_server); 24 | uv_tcp_bind(&_server, (const struct sockaddr*) &addr, 0); 25 | uv_listen((uv_stream_t*)&_server, 8, tinyweb_on_connection); 26 | } 27 | 28 | static void after_uv_close(uv_handle_t* handle) { 29 | free(handle); // uv_tcp_t* client, see tinyweb_on_connection() 30 | } 31 | 32 | static void after_uv_write(uv_write_t* w, int status) { 33 | if(w->data) 34 | free(w->data); 35 | uv_close((uv_handle_t*)w->handle, after_uv_close); // close client 36 | free(w); 37 | } 38 | 39 | static void write_uv_data(uv_stream_t* stream, const void* data, unsigned int len, int need_copy_data) { 40 | uv_buf_t buf; 41 | uv_write_t* w; 42 | void* newdata = (void*)data; 43 | 44 | if(data == NULL || len == 0) return; 45 | if(len ==(unsigned int)-1) 46 | len = strlen(data); 47 | 48 | if(need_copy_data) { 49 | newdata = malloc(len); 50 | memcpy(newdata, data, len); 51 | } 52 | 53 | buf = uv_buf_init(newdata, len); 54 | w = (uv_write_t*)malloc(sizeof(uv_write_t)); 55 | w->data = need_copy_data ? newdata : NULL; 56 | uv_write(w, stream, &buf, 1, after_uv_write); // free w and w->data in after_uv_write() 57 | } 58 | 59 | static const char* http_respone = "HTTP/1.1 200 OK\r\n" 60 | "Content-Type:text/html;charset=utf-8\r\n" 61 | "Content-Length:18\r\n" 62 | "\r\n" 63 | "Welcome to tinyweb"; 64 | 65 | static void tinyweb_on_connection(uv_stream_t* server, int status) { 66 | assert(server == (uv_stream_t*)&_server); 67 | if(status == 0) { 68 | uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); 69 | uv_tcp_init(_loop, client); 70 | uv_accept((uv_stream_t*)&_server, (uv_stream_t*)client); 71 | write_uv_data((uv_stream_t*)client, http_respone, -1, 0); 72 | //close client after uv_write, and free it in after_uv_close() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tinyweb1.h: -------------------------------------------------------------------------------- 1 | #ifndef __TINYWEB_H__ 2 | #define __TINYWEB_H__ 3 | 4 | #include 5 | 6 | void tinyweb_start(uv_loop_t* loop, const char* ip, int port); 7 | 8 | #endif //__TINYWEB_H__ 9 | -------------------------------------------------------------------------------- /tinyweb2.c: -------------------------------------------------------------------------------- 1 | #include "tinyweb2.h" 2 | #include "membuf.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //Tinyweb v2, a tiny web server based on libuv, by liigo, 2013-6-24. 11 | 12 | uv_tcp_t _server; 13 | uv_tcp_t _client; 14 | uv_loop_t* _loop = NULL; 15 | 16 | static void tinyweb_on_connection(uv_stream_t* server, int status); 17 | 18 | //start web server, linstening ip:port 19 | //ip can be NULL or "", which means "0.0.0.0" 20 | void tinyweb_start(uv_loop_t* loop, const char* ip, int port) { 21 | struct sockaddr_in addr; 22 | uv_ip4_addr((ip && ip[0]) ? ip : "0.0.0.0", port, &addr); 23 | _loop = loop; 24 | uv_tcp_init(_loop, &_server); 25 | uv_tcp_bind(&_server, (const struct sockaddr*) &addr, 0); 26 | uv_listen((uv_stream_t*)&_server, 8, tinyweb_on_connection); 27 | } 28 | 29 | static void after_uv_close_client(uv_handle_t* client) { 30 | membuf_uninit((membuf_t*)client->data); //see: tinyweb_on_connection() 31 | free(client->data); //membuf_t*: request buffer 32 | free(client); 33 | } 34 | 35 | static void after_uv_write(uv_write_t* w, int status) { 36 | if(w->data) 37 | free(w->data); //copyed data 38 | uv_close((uv_handle_t*)w->handle, after_uv_close_client); 39 | free(w); 40 | } 41 | 42 | //close the connect of a client 43 | static void tinyweb_close_client(uv_stream_t* client) { 44 | uv_close((uv_handle_t*)client, after_uv_close_client); 45 | } 46 | 47 | //write data to client 48 | //data: the data to be sent 49 | //len: the size of data, can be -1 if data is string 50 | //need_copy_data: copy data or not 51 | //need_free_data: free data or not, ignore this arg if need_copy_data is non-zero 52 | //write_uv_data() will close client connection after writien success, because tinyweb use short connection. 53 | static void write_uv_data(uv_stream_t* client, const void* data, unsigned int len, int need_copy_data, int need_free_data) { 54 | uv_buf_t buf; 55 | uv_write_t* w; 56 | void* newdata = (void*)data; 57 | 58 | if(data == NULL || len == 0) return; 59 | if(len ==(unsigned int)-1) 60 | len = strlen((char*)data); 61 | 62 | if(need_copy_data) { 63 | newdata = malloc(len); 64 | memcpy(newdata, data, len); 65 | } 66 | 67 | buf = uv_buf_init((char*)newdata, len); 68 | w = (uv_write_t*)malloc(sizeof(uv_write_t)); 69 | w->data = (need_copy_data || need_free_data) ? newdata : NULL; 70 | uv_write(w, client, &buf, 1, after_uv_write); //free w and w->data in after_uv_write() 71 | } 72 | 73 | //status: "200 OK" 74 | //content_type: "text/html" 75 | //content: any utf-8 data, need html-encode if content_type is "text/html" 76 | //content_length: can be -1 if content is string 77 | //returns malloc()ed respone, need free() by caller 78 | char* format_http_respone(const char* status, const char* content_type, const void* content, int content_length) { 79 | int totalsize; 80 | char* respone; 81 | if(content_length < 0) 82 | content_length = content ? strlen((char*)content) : 0; 83 | totalsize = strlen(status) + strlen(content_type) + content_length + 128; 84 | respone = (char*) malloc(totalsize); 85 | sprintf(respone, "HTTP/1.1 %s\r\n" 86 | "Content-Type:%s;charset=utf-8\r\n" 87 | "Content-Length:%d\r\n\r\n", 88 | status, content_type, content_length); 89 | if(content) { 90 | memcpy(respone + strlen(respone), content, content_length); 91 | } 92 | return respone; 93 | } 94 | 95 | #if defined(WIN32) 96 | #define snprintf _snprintf 97 | #endif 98 | 99 | //invoked by tinyweb when GET request comes in 100 | //please invoke write_uv_data() once and only once on every request, to send respone to client and close the connection. 101 | //if not handle this request (by invoking write_uv_data()), you can close connection using tinyweb_close_client(client). 102 | //pathinfo: "/" or "/book/view/1" 103 | //query_stirng: the string after '?' in url, such as "id=0&value=123", maybe NULL or "" 104 | static void tinyweb_on_request_get(uv_stream_t* client, const char* pathinfo, const char* query_stirng) { 105 | if(strcmp(pathinfo, "/") == 0) { 106 | char* respone = format_http_respone("200 OK", "text/html", "Welcome to tinyweb", -1); 107 | write_uv_data(client, respone, -1, 0, 1); 108 | } else if(strcmp(pathinfo, "/404") == 0) { 109 | char* respone = format_http_respone("404 Not Found", "text/html", "

404 Page Not Found

", -1); 110 | write_uv_data(client, respone, -1, 0, 1); 111 | } else { 112 | char* respone; 113 | char content[1024]; 114 | snprintf(content, sizeof(content), "

pathinfo: %s

query stirng: %s

", pathinfo, query_stirng); 115 | respone = format_http_respone("200 OK", "text/html", content, -1); 116 | write_uv_data(client, respone, -1, 0, 1); 117 | } 118 | } 119 | 120 | static void on_uv_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { 121 | *buf = uv_buf_init(malloc(suggested_size), suggested_size); 122 | } 123 | 124 | static void on_uv_read(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf) { 125 | if(nread > 0) { 126 | char* crln2; 127 | membuf_t* membuf = (membuf_t*) client->data; //see tinyweb_on_connection() 128 | assert(membuf); 129 | membuf_append_data(membuf, buf->base, nread); 130 | if((crln2 = strstr((const char*)membuf->data, "\r\n\r\n")) != NULL) { 131 | const char* request_header = membuf->data; 132 | *crln2 = '\0'; 133 | printf("\n----Tinyweb client request: ----\n%s\n", request_header); 134 | //handle GET request 135 | if(request_header[0]=='G' && request_header[1]=='E' && request_header[2]=='T') { 136 | char *query_stirng, *end; 137 | const char* pathinfo = request_header + 3; 138 | while(isspace(*pathinfo)) pathinfo++; 139 | end = strchr(pathinfo, ' '); 140 | if(end) *end = '\0'; 141 | query_stirng = strchr(pathinfo, '?'); //split pathinfo and query_stirng using '?' 142 | if(query_stirng) { 143 | *query_stirng = '\0'; 144 | query_stirng++; 145 | } 146 | tinyweb_on_request_get(client, pathinfo, query_stirng); 147 | //write_uv_data -> after_uv_write -> uv_close, will close the client, so additional processing is not needed. 148 | } else { 149 | tinyweb_close_client(client); 150 | } 151 | } 152 | } else if(nread == -1) { 153 | tinyweb_close_client(client); 154 | } 155 | 156 | if(buf->base) 157 | free(buf->base); 158 | } 159 | 160 | static void tinyweb_on_connection(uv_stream_t* server, int status) { 161 | assert(server == (uv_stream_t*)&_server); 162 | if(status == 0) { 163 | uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); 164 | client->data = malloc(sizeof(membuf_t)); 165 | membuf_init((membuf_t*)client->data, 128); 166 | uv_tcp_init(_loop, client); 167 | uv_accept((uv_stream_t*)&_server, (uv_stream_t*)client); 168 | uv_read_start((uv_stream_t*)client, on_uv_alloc, on_uv_read); 169 | 170 | //write_uv_data((uv_stream_t*)client, http_respone, -1, 0); 171 | //close client after uv_write, and free it in after_uv_close() 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /tinyweb2.h: -------------------------------------------------------------------------------- 1 | #ifndef __TINYWEB_H__ 2 | #define __TINYWEB_H__ 3 | 4 | #include 5 | 6 | void tinyweb_start(uv_loop_t* loop, const char* ip, int port); 7 | 8 | #endif //__TINYWEB_H__ 9 | -------------------------------------------------------------------------------- /tinyweb3.c: -------------------------------------------------------------------------------- 1 | #include "tinyweb3.h" 2 | #include "membuf.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //Tinyweb v3, a tiny web server based on libuv, by liigo, 2013-6-30. 11 | 12 | uv_tcp_t _server; 13 | uv_tcp_t _client; 14 | uv_loop_t* _loop = NULL; 15 | const char* _doc_root_path = NULL; 16 | 17 | static void tinyweb_on_connection(uv_stream_t* server, int status); 18 | 19 | //start web server, linstening ip:port 20 | //ip can be NULL or "", which means "0.0.0.0" 21 | //doc_root_path can be NULL, or requires not end with / 22 | void tinyweb_start(uv_loop_t* loop, const char* ip, int port, const char* doc_root_path) { 23 | struct sockaddr_in addr; 24 | uv_ip4_addr((ip && ip[0]) ? ip : "0.0.0.0", port, &addr); 25 | 26 | _loop = loop; 27 | if(doc_root_path && doc_root_path[0]) 28 | _doc_root_path = doc_root_path; 29 | 30 | uv_tcp_init(_loop, &_server); 31 | uv_tcp_bind(&_server, (const struct sockaddr*) &addr, 0); 32 | uv_listen((uv_stream_t*)&_server, 8, tinyweb_on_connection); 33 | 34 | printf("Tinyweb v3 is started, listening port %d...\n", port); 35 | printf("Please access http://localhost:%d from you web browser.\n", port); 36 | } 37 | 38 | static void after_uv_close_client(uv_handle_t* client) { 39 | membuf_uninit((membuf_t*)client->data); //see: tinyweb_on_connection() 40 | free(client->data); //membuf_t*: request buffer 41 | free(client); 42 | } 43 | 44 | static void after_uv_write(uv_write_t* w, int status) { 45 | if(w->data) 46 | free(w->data); //copyed data 47 | uv_close((uv_handle_t*)w->handle, after_uv_close_client); 48 | free(w); 49 | } 50 | 51 | //close the connect of a client 52 | static void tinyweb_close_client(uv_stream_t* client) { 53 | uv_close((uv_handle_t*)client, after_uv_close_client); 54 | } 55 | 56 | //write data to client 57 | //data: the data to be sent 58 | //len: the size of data, can be -1 if data is string 59 | //need_copy_data: copy data or not 60 | //need_free_data: free data or not, ignore this arg if need_copy_data is non-zero 61 | //write_uv_data() will close client connection after writien success, because tinyweb use short connection. 62 | static void write_uv_data(uv_stream_t* client, const void* data, unsigned int len, int need_copy_data, int need_free_data) { 63 | uv_buf_t buf; 64 | uv_write_t* w; 65 | void* newdata = (void*)data; 66 | 67 | if(data == NULL || len == 0) return; 68 | if(len ==(unsigned int)-1) 69 | len = strlen((char*)data); 70 | 71 | if(need_copy_data) { 72 | newdata = malloc(len); 73 | memcpy(newdata, data, len); 74 | } 75 | 76 | buf = uv_buf_init((char*)newdata, len); 77 | w = (uv_write_t*)malloc(sizeof(uv_write_t)); 78 | w->data = (need_copy_data || need_free_data) ? newdata : NULL; 79 | uv_write(w, client, &buf, 1, after_uv_write); //free w and w->data in after_uv_write() 80 | } 81 | 82 | //status: "200 OK" 83 | //content_type: "text/html" 84 | //content: any utf-8 data, need html-encode if content_type is "text/html" 85 | //content_length: can be -1 if content is string 86 | //respone_size: if not NULL, the size of respone will be writen to it 87 | //returns malloc()ed respone, need free() by caller 88 | char* format_http_respone(const char* status, const char* content_type, const void* content, int content_length, int* respone_size) { 89 | int totalsize, header_size; 90 | char* respone; 91 | if(content_length < 0) 92 | content_length = content ? strlen((char*)content) : 0; 93 | totalsize = strlen(status) + strlen(content_type) + content_length + 128; 94 | respone = (char*) malloc(totalsize); 95 | header_size = sprintf(respone, "HTTP/1.1 %s\r\n" 96 | "Content-Type:%s;charset=utf-8\r\n" 97 | "Content-Length:%d\r\n\r\n", 98 | status, content_type, content_length); 99 | assert(header_size > 0); 100 | if(content) { 101 | memcpy(respone + header_size, content, content_length); 102 | } 103 | if(respone_size) 104 | *respone_size = header_size + content_length; 105 | return respone; 106 | } 107 | 108 | #if defined(WIN32) 109 | #define snprintf _snprintf 110 | #endif 111 | 112 | static void _404_not_found(uv_stream_t* client, const char* pathinfo) { 113 | char* respone; 114 | char buffer[1024]; 115 | snprintf(buffer, sizeof(buffer), "

404 Not Found

%s

", pathinfo); 116 | respone = format_http_respone("404 Not Found", "text/html", buffer, -1, NULL); 117 | write_uv_data(client, respone, -1, 0, 1); 118 | } 119 | 120 | //invoked by tinyweb when a file is request. see tinyweb_on_request_get() 121 | static void _on_send_file(uv_stream_t* client, const char* content_type, const char* file, const char* pathinfo) { 122 | int file_size, read_bytes, respone_size; 123 | unsigned char *file_data, *respone; 124 | FILE* fp = fopen(file, "rb"); 125 | if(fp) { 126 | fseek(fp, 0, SEEK_END); 127 | file_size = ftell(fp); 128 | fseek(fp, 0, SEEK_SET); 129 | file_data = (unsigned char*) malloc(file_size); 130 | read_bytes = fread(file_data, 1, file_size, fp); 131 | assert(read_bytes == file_size); 132 | fclose(fp); 133 | 134 | respone_size = 0; 135 | respone = format_http_respone("200 OK", content_type, file_data, file_size, &respone_size); 136 | free(file_data); 137 | write_uv_data(client, respone, respone_size, 0, 1); 138 | } else { 139 | _404_not_found(client, pathinfo); 140 | } 141 | } 142 | 143 | //only identify familiar postfix currently 144 | static const char* _get_content_type(const char* postfix) { 145 | if(strcmp(postfix, "html") == 0 || strcmp(postfix, "htm") == 0) 146 | return "text/html"; 147 | else if(strcmp(postfix, "js") == 0) 148 | return "text/javascript"; 149 | else if(strcmp(postfix, "css") == 0) 150 | return "text/css"; 151 | else if(strcmp(postfix, "jpeg") == 0 || strcmp(postfix, "jpg") == 0) 152 | return "image/jpeg"; 153 | else if(strcmp(postfix, "png") == 0) 154 | return "image/png"; 155 | else if(strcmp(postfix, "gif") == 0) 156 | return "image/gif"; 157 | else if(strcmp(postfix, "txt") == 0) 158 | return "text/plain"; 159 | else 160 | return "application/octet-stream"; 161 | } 162 | 163 | //invoked by tinyweb when GET request comes in 164 | //please invoke write_uv_data() once and only once on every request, to send respone to client and close the connection. 165 | //if not handle this request (by invoking write_uv_data()), you can close connection using tinyweb_close_client(client). 166 | //pathinfo: "/" or "/book/view/1" 167 | //query_stirng: the string after '?' in url, such as "id=0&value=123", maybe NULL or "" 168 | static void tinyweb_on_request_get(uv_stream_t* client, const char* pathinfo, const char* query_stirng) { 169 | //request a file? 170 | char* postfix = strrchr(pathinfo, '.'); 171 | if(postfix) { 172 | postfix++; 173 | if(_doc_root_path) { 174 | char file[1024]; 175 | snprintf(file, sizeof(file), "%s%s", _doc_root_path, pathinfo); 176 | _on_send_file(client, _get_content_type(postfix), file, pathinfo); 177 | return; 178 | } else { 179 | _404_not_found(client, pathinfo); 180 | return; 181 | } 182 | } 183 | 184 | //request an action 185 | if(strcmp(pathinfo, "/") == 0) { 186 | char* respone = format_http_respone("200 OK", "text/html", "Welcome to tinyweb. index.html", -1, NULL); 187 | write_uv_data(client, respone, -1, 0, 1); 188 | } else if(strcmp(pathinfo, "/404") == 0) { 189 | char* respone = format_http_respone("404 Not Found", "text/html", "

404 Page Not Found

", -1, NULL); 190 | write_uv_data(client, respone, -1, 0, 1); 191 | } else { 192 | char* respone; 193 | char content[1024]; 194 | snprintf(content, sizeof(content), "

tinyweb

pathinfo: %s

query stirng: %s

", pathinfo, query_stirng); 195 | respone = format_http_respone("200 OK", "text/html", content, -1, NULL); 196 | write_uv_data(client, respone, -1, 0, 1); 197 | } 198 | } 199 | 200 | static void on_uv_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { 201 | *buf = uv_buf_init(malloc(suggested_size), suggested_size); 202 | } 203 | 204 | static void on_uv_read(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf) { 205 | if(nread > 0) { 206 | char* crln2; 207 | membuf_t* membuf = (membuf_t*) client->data; //see tinyweb_on_connection() 208 | assert(membuf); 209 | membuf_append_data(membuf, buf->base, nread); 210 | if((crln2 = strstr((const char*)membuf->data, "\r\n\r\n")) != NULL) { 211 | const char* request_header = membuf->data; 212 | *crln2 = '\0'; 213 | printf("\n----Tinyweb client request: ----\n%s\n", request_header); 214 | //handle GET request 215 | if(request_header[0]=='G' && request_header[1]=='E' && request_header[2]=='T') { 216 | char *query_stirng, *end; 217 | const char* pathinfo = request_header + 3; 218 | while(isspace(*pathinfo)) pathinfo++; 219 | end = strchr(pathinfo, ' '); 220 | if(end) *end = '\0'; 221 | query_stirng = strchr(pathinfo, '?'); //split pathinfo and query_stirng using '?' 222 | if(query_stirng) { 223 | *query_stirng = '\0'; 224 | query_stirng++; 225 | } 226 | tinyweb_on_request_get(client, pathinfo, query_stirng); 227 | //write_uv_data -> after_uv_write -> uv_close, will close the client, so additional processing is not needed. 228 | } else { 229 | tinyweb_close_client(client); 230 | } 231 | } 232 | } else if(nread == -1) { 233 | tinyweb_close_client(client); 234 | } 235 | 236 | if(buf->base) 237 | free(buf->base); 238 | } 239 | 240 | static void tinyweb_on_connection(uv_stream_t* server, int status) { 241 | assert(server == (uv_stream_t*)&_server); 242 | if(status == 0) { 243 | uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); 244 | client->data = malloc(sizeof(membuf_t)); 245 | membuf_init((membuf_t*)client->data, 128); 246 | uv_tcp_init(_loop, client); 247 | uv_accept((uv_stream_t*)&_server, (uv_stream_t*)client); 248 | uv_read_start((uv_stream_t*)client, on_uv_alloc, on_uv_read); 249 | 250 | //write_uv_data((uv_stream_t*)client, http_respone, -1, 0); 251 | //close client after uv_write, and free it in after_uv_close() 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /tinyweb3.h: -------------------------------------------------------------------------------- 1 | #ifndef __TINYWEB_H__ 2 | #define __TINYWEB_H__ 3 | 4 | #include 5 | 6 | void tinyweb_start(uv_loop_t* loop, const char* ip, int port, const char* doc_root_path); 7 | 8 | #endif //__TINYWEB_H__ 9 | -------------------------------------------------------------------------------- /win32/tinyweb.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "tinyweb1"=.\tinyweb1.dsp - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Project: "tinyweb2"=.\tinyweb2.dsp - Package Owner=<4> 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<4> 25 | {{{ 26 | }}} 27 | 28 | ############################################################################### 29 | 30 | Project: "tinyweb3"=.\tinyweb3.dsp - Package Owner=<4> 31 | 32 | Package=<5> 33 | {{{ 34 | }}} 35 | 36 | Package=<4> 37 | {{{ 38 | }}} 39 | 40 | ############################################################################### 41 | 42 | Global: 43 | 44 | Package=<5> 45 | {{{ 46 | }}} 47 | 48 | Package=<3> 49 | {{{ 50 | }}} 51 | 52 | ############################################################################### 53 | 54 | -------------------------------------------------------------------------------- /win32/tinyweb1.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="tinyweb1" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103 6 | 7 | CFG=tinyweb1 - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "tinyweb1.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "tinyweb1.mak" CFG="tinyweb1 - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "tinyweb1 - Win32 Release" (based on "Win32 (x86) Console Application") 21 | !MESSAGE "tinyweb1 - Win32 Debug" (based on "Win32 (x86) Console Application") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | RSC=rc.exe 30 | 31 | !IF "$(CFG)" == "tinyweb1 - Win32 Release" 32 | 33 | # PROP BASE Use_MFC 0 34 | # PROP BASE Use_Debug_Libraries 0 35 | # PROP BASE Output_Dir "Release" 36 | # PROP BASE Intermediate_Dir "Release" 37 | # PROP BASE Target_Dir "" 38 | # PROP Use_MFC 0 39 | # PROP Use_Debug_Libraries 0 40 | # PROP Output_Dir "Release" 41 | # PROP Intermediate_Dir "Release" 42 | # PROP Ignore_Export_Lib 0 43 | # PROP Target_Dir "" 44 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 45 | # ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 46 | # ADD BASE RSC /l 0x804 /d "NDEBUG" 47 | # ADD RSC /l 0x804 /d "NDEBUG" 48 | BSC32=bscmake.exe 49 | # ADD BASE BSC32 /nologo 50 | # ADD BSC32 /nologo 51 | LINK32=link.exe 52 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 53 | # ADD LINK32 libuv.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 54 | 55 | !ELSEIF "$(CFG)" == "tinyweb1 - Win32 Debug" 56 | 57 | # PROP BASE Use_MFC 0 58 | # PROP BASE Use_Debug_Libraries 1 59 | # PROP BASE Output_Dir "Debug" 60 | # PROP BASE Intermediate_Dir "Debug" 61 | # PROP BASE Target_Dir "" 62 | # PROP Use_MFC 0 63 | # PROP Use_Debug_Libraries 1 64 | # PROP Output_Dir "Debug" 65 | # PROP Intermediate_Dir "Debug" 66 | # PROP Ignore_Export_Lib 0 67 | # PROP Target_Dir "" 68 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 69 | # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 70 | # ADD BASE RSC /l 0x804 /d "_DEBUG" 71 | # ADD RSC /l 0x804 /d "_DEBUG" 72 | BSC32=bscmake.exe 73 | # ADD BASE BSC32 /nologo 74 | # ADD BSC32 /nologo 75 | LINK32=link.exe 76 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 77 | # ADD LINK32 libuvd.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 78 | 79 | !ENDIF 80 | 81 | # Begin Target 82 | 83 | # Name "tinyweb1 - Win32 Release" 84 | # Name "tinyweb1 - Win32 Debug" 85 | # Begin Group "Source Files" 86 | 87 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 88 | # Begin Source File 89 | 90 | SOURCE=..\test\main1.c 91 | # End Source File 92 | # Begin Source File 93 | 94 | SOURCE=..\tinyweb1.c 95 | # End Source File 96 | # End Group 97 | # Begin Group "Header Files" 98 | 99 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 100 | # Begin Source File 101 | 102 | SOURCE=..\tinyweb1.h 103 | # End Source File 104 | # End Group 105 | # Begin Group "Resource Files" 106 | 107 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 108 | # End Group 109 | # End Target 110 | # End Project 111 | -------------------------------------------------------------------------------- /win32/tinyweb2.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="tinyweb2" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103 6 | 7 | CFG=tinyweb2 - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "tinyweb2.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "tinyweb2.mak" CFG="tinyweb2 - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "tinyweb2 - Win32 Release" (based on "Win32 (x86) Console Application") 21 | !MESSAGE "tinyweb2 - Win32 Debug" (based on "Win32 (x86) Console Application") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | RSC=rc.exe 30 | 31 | !IF "$(CFG)" == "tinyweb2 - Win32 Release" 32 | 33 | # PROP BASE Use_MFC 0 34 | # PROP BASE Use_Debug_Libraries 0 35 | # PROP BASE Output_Dir "Release" 36 | # PROP BASE Intermediate_Dir "Release" 37 | # PROP BASE Target_Dir "" 38 | # PROP Use_MFC 0 39 | # PROP Use_Debug_Libraries 0 40 | # PROP Output_Dir "Release" 41 | # PROP Intermediate_Dir "Release" 42 | # PROP Ignore_Export_Lib 0 43 | # PROP Target_Dir "" 44 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 45 | # ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 46 | # ADD BASE RSC /l 0x804 /d "NDEBUG" 47 | # ADD RSC /l 0x804 /d "NDEBUG" 48 | BSC32=bscmake.exe 49 | # ADD BASE BSC32 /nologo 50 | # ADD BSC32 /nologo 51 | LINK32=link.exe 52 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 53 | # ADD LINK32 libuv.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 54 | 55 | !ELSEIF "$(CFG)" == "tinyweb2 - Win32 Debug" 56 | 57 | # PROP BASE Use_MFC 0 58 | # PROP BASE Use_Debug_Libraries 1 59 | # PROP BASE Output_Dir "Debug" 60 | # PROP BASE Intermediate_Dir "Debug" 61 | # PROP BASE Target_Dir "" 62 | # PROP Use_MFC 0 63 | # PROP Use_Debug_Libraries 1 64 | # PROP Output_Dir "Debug" 65 | # PROP Intermediate_Dir "Debug" 66 | # PROP Ignore_Export_Lib 0 67 | # PROP Target_Dir "" 68 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 69 | # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 70 | # ADD BASE RSC /l 0x804 /d "_DEBUG" 71 | # ADD RSC /l 0x804 /d "_DEBUG" 72 | BSC32=bscmake.exe 73 | # ADD BASE BSC32 /nologo 74 | # ADD BSC32 /nologo 75 | LINK32=link.exe 76 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 77 | # ADD LINK32 libuvd.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 78 | 79 | !ENDIF 80 | 81 | # Begin Target 82 | 83 | # Name "tinyweb2 - Win32 Release" 84 | # Name "tinyweb2 - Win32 Debug" 85 | # Begin Group "Source Files" 86 | 87 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 88 | # Begin Source File 89 | 90 | SOURCE=..\test\main2.c 91 | # End Source File 92 | # Begin Source File 93 | 94 | SOURCE=..\membuf.c 95 | # End Source File 96 | # Begin Source File 97 | 98 | SOURCE=..\tinyweb2.c 99 | # End Source File 100 | # End Group 101 | # Begin Group "Header Files" 102 | 103 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 104 | # Begin Source File 105 | 106 | SOURCE=..\membuf.h 107 | # End Source File 108 | # Begin Source File 109 | 110 | SOURCE=..\tinyweb2.h 111 | # End Source File 112 | # End Group 113 | # Begin Group "Resource Files" 114 | 115 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 116 | # End Group 117 | # End Target 118 | # End Project 119 | -------------------------------------------------------------------------------- /win32/tinyweb3.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="tinyweb3" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103 6 | 7 | CFG=tinyweb3 - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "tinyweb3.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "tinyweb3.mak" CFG="tinyweb3 - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "tinyweb3 - Win32 Release" (based on "Win32 (x86) Console Application") 21 | !MESSAGE "tinyweb3 - Win32 Debug" (based on "Win32 (x86) Console Application") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | RSC=rc.exe 30 | 31 | !IF "$(CFG)" == "tinyweb3 - Win32 Release" 32 | 33 | # PROP BASE Use_MFC 0 34 | # PROP BASE Use_Debug_Libraries 0 35 | # PROP BASE Output_Dir "Release" 36 | # PROP BASE Intermediate_Dir "Release" 37 | # PROP BASE Target_Dir "" 38 | # PROP Use_MFC 0 39 | # PROP Use_Debug_Libraries 0 40 | # PROP Output_Dir "Release" 41 | # PROP Intermediate_Dir "Release" 42 | # PROP Ignore_Export_Lib 0 43 | # PROP Target_Dir "" 44 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 45 | # ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c 46 | # ADD BASE RSC /l 0x804 /d "NDEBUG" 47 | # ADD RSC /l 0x804 /d "NDEBUG" 48 | BSC32=bscmake.exe 49 | # ADD BASE BSC32 /nologo 50 | # ADD BSC32 /nologo 51 | LINK32=link.exe 52 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 53 | # ADD LINK32 libuv.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 54 | 55 | !ELSEIF "$(CFG)" == "tinyweb3 - Win32 Debug" 56 | 57 | # PROP BASE Use_MFC 0 58 | # PROP BASE Use_Debug_Libraries 1 59 | # PROP BASE Output_Dir "Debug" 60 | # PROP BASE Intermediate_Dir "Debug" 61 | # PROP BASE Target_Dir "" 62 | # PROP Use_MFC 0 63 | # PROP Use_Debug_Libraries 1 64 | # PROP Output_Dir "Debug" 65 | # PROP Intermediate_Dir "Debug" 66 | # PROP Ignore_Export_Lib 0 67 | # PROP Target_Dir "" 68 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 69 | # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 70 | # ADD BASE RSC /l 0x804 /d "_DEBUG" 71 | # ADD RSC /l 0x804 /d "_DEBUG" 72 | BSC32=bscmake.exe 73 | # ADD BASE BSC32 /nologo 74 | # ADD BSC32 /nologo 75 | LINK32=link.exe 76 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 77 | # ADD LINK32 libuvd.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 78 | 79 | !ENDIF 80 | 81 | # Begin Target 82 | 83 | # Name "tinyweb3 - Win32 Release" 84 | # Name "tinyweb3 - Win32 Debug" 85 | # Begin Group "Source Files" 86 | 87 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 88 | # Begin Source File 89 | 90 | SOURCE=..\test\main3.c 91 | # End Source File 92 | # Begin Source File 93 | 94 | SOURCE=..\membuf.c 95 | # End Source File 96 | # Begin Source File 97 | 98 | SOURCE=..\tinyweb3.c 99 | # End Source File 100 | # End Group 101 | # Begin Group "Header Files" 102 | 103 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 104 | # Begin Source File 105 | 106 | SOURCE=..\membuf.h 107 | # End Source File 108 | # Begin Source File 109 | 110 | SOURCE=..\tinyweb3.h 111 | # End Source File 112 | # End Group 113 | # Begin Group "Resource Files" 114 | 115 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 116 | # End Group 117 | # End Target 118 | # End Project 119 | --------------------------------------------------------------------------------