klhttp-internal.c
上传用户:jnmzc84
上传日期:2022-08-08
资源大小:35k
文件大小:8k
源码类别:

网络编程

开发平台:

Visual C++

  1. /**
  2.   @file klhttp-internal.c
  3.   @author Kevin Lynx
  4.   @data 7.25.2008
  5.   @brief for klhttpd internal use.
  6. */
  7. #include "klhttp-config.h"
  8. #include "klhttp-internal.h"
  9. #include <malloc.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <time.h>
  13. #include "evbuffer.h"
  14. #define NEW( type ) (type*) malloc( sizeof( type ) )
  15. /**
  16.   parse http request initial line.
  17. */
  18. static int _parse_init_line( struct http_request *request, char *line )
  19. {
  20. char *token = strtok( line, " " );
  21. /* method */
  22. if( strcmp( token, "GET" ) == 0 )
  23. {
  24. request->type = HTTP_GET;
  25. }
  26. else if( strcmp( token, "HEAD" ) == 0 )
  27. {
  28. request->type = HTTP_HEAD;
  29. }
  30. else
  31. {
  32. request->type = HTTP_UNKNOWN;
  33. }
  34. /* uri */
  35. token = strtok( 0, " " );
  36. request->uri = (char*) malloc( strlen( token ) + 1 );
  37. strcpy( request->uri, token );
  38. /* http protocol version */
  39. token = strtok( 0, " " );
  40. if( strcmp( token, "HTTP/1.0" ) == 0 )
  41. {
  42. request->ver.major = 1;
  43. request->ver.minor = 0;
  44. }
  45. else if( strcmp( token, "HTTP/1.1" ) == 0 )
  46. {
  47. request->ver.major = 1;
  48. request->ver.minor = 1;
  49. }
  50. else
  51. {
  52. request->ver.major = 1;
  53. request->ver.major = 0;
  54. }
  55. return 0;
  56. }
  57. /**
  58.   add response headers
  59. */
  60. static void _add_headers( struct http_header_head *headers, const char *name, const char *value )
  61. {
  62. struct http_header *header = NEW( struct http_header );
  63. header->name = (char*) malloc( strlen( name ) + 1 );
  64. header->value = (char*) malloc( strlen( value ) + 1 );
  65. strcpy( header->name, name );
  66. strcpy( header->value, value );
  67. TAILQ_INSERT_TAIL( headers, header, next );
  68. }
  69. /**
  70.   add time header
  71. */
  72. static void _add_time_header( struct evbuffer *buf )
  73. {
  74. char date[50];
  75. #ifndef WIN32
  76. struct tm cur;
  77. #endif
  78. struct tm *cur_p;
  79. time_t t = time( NULL );
  80. #ifdef WIN32
  81. cur_p = gmtime( &t );
  82. #else
  83. gmtime_r( &t, &cur );
  84. cur_p = &cur;
  85. #endif
  86. strftime( date, sizeof( date ), "%a, %d %b %Y %H:%M:%S GMT", cur_p);
  87. evbuffer_add_printf( buf, "Date: %srn", date );
  88. }
  89. /**
  90.   get an uri's mime string.
  91. */
  92. static const char *_get_mime_type( const char *uri, char *buf )
  93. {
  94. const char *t = uri + strlen( uri );
  95. char type[64];
  96. for( ; t >= uri && *t != '.'; -- t )
  97. {
  98. /* until '.'*/
  99. ;
  100. }
  101. strcpy( type, t + 1 );
  102. /* append mime header */
  103. if( strcmp( type, "html" ) == 0 || 
  104. strcmp( type, "htm" ) == 0 )
  105. {
  106. sprintf( buf, "text/%s", type );
  107. }
  108. else if( strcmp( type, "gif" ) == 0 ||
  109. strcmp( type, "jpg" ) == 0 ||
  110. strcmp( type, "jpeg" ) == 0 ||
  111. strcmp( type, "png" ) == 0 )
  112. {
  113. sprintf( buf, "image/%s", type );
  114. }
  115. else if( strcmp( type, "/" ) == 0 )
  116. {
  117. /* the default value */
  118. sprintf( buf, "text/html" );
  119. }
  120. else
  121. {
  122. /* unknown error */
  123. sprintf( buf, "unknown" );
  124. }
  125. return buf;
  126. }
  127. /**
  128.   check the whether the request is valid, if not, it will write the error response.
  129.   @return if the request is valid return 0.
  130. */
  131. static int _check_request_valid( struct evbuffer *buf, const struct http_request *request )
  132. {
  133. if( request->type == HTTP_UNKNOWN )
  134. {
  135. /* not implemented method */
  136. http_response_error( buf, HTTP_NOTIMPLEMENT, CODE_STR( HTTP_NOTIMPLEMENT ), "Not Implemented Method" );
  137. return -1;
  138. }
  139. /* HTTP 1.1 needs Host header */
  140. if( request->ver.major == 1 && request->ver.minor == 1 )
  141. {
  142. const char *host = http_get_header_value( request->headers, "Host" );
  143. if( host == 0 )
  144. {
  145. /* bad request */
  146. http_response_error( buf, HTTP_BADREQUEST, CODE_STR( HTTP_BADREQUEST ), "Bad Request : needs Host header" );
  147. return -1;
  148. }
  149. }
  150. return 0;
  151. }
  152. struct http_header_head *http_header_new()
  153. {
  154. struct http_header_head *queue = NEW( struct http_header_head );
  155. if( queue == 0 )
  156. {
  157. return 0;
  158. }
  159. TAILQ_INIT( queue );
  160. return queue;
  161. }
  162. void http_header_free( struct http_header_head *header_queue )
  163. {
  164. struct http_header *header, *prev = 0;
  165. TAILQ_FOREACH( header, header_queue, next )
  166. {
  167. if( prev != 0 )
  168. {
  169. free( prev );
  170. }
  171. free( header->name );
  172. free( header->value );
  173. prev = header;
  174. }
  175. free( header_queue );
  176. }
  177. int http_add_header( struct http_header_head *header_queue, char *line )
  178. {
  179. char *value ;
  180. char *name = strchr( line, ':' );
  181. struct http_header *header = NEW( struct http_header );
  182. header->name = (char*) malloc( name - line + 1 );
  183. strncpy( header->name, line, name - line );
  184. header->name[name-line] = '';
  185. for( value = name + 1; *value == ' '; ++ value )
  186. {
  187. /* until a no-space character. */
  188. ;
  189. }
  190. header->value = (char*) malloc( strlen( line ) - ( value - line ) + 1 );
  191. strcpy( header->value, value );
  192. TAILQ_INSERT_TAIL( header_queue, header, next );
  193. return 0;
  194. }
  195. const char *http_get_header_value( struct http_header_head *header_queue, const char *header_name )
  196. {
  197. struct http_header *header;
  198. TAILQ_FOREACH( header, header_queue, next )
  199. {
  200. if( strcmp( header->name, header_name ) == 0 )
  201. {
  202. return header->value;
  203. }
  204. }
  205. return 0;
  206. }
  207. struct http_request *http_request_parse( struct evbuffer *buf )
  208. {
  209. struct http_request *request = NEW( struct http_request );
  210. if( request == 0 )
  211. {
  212. return 0;
  213. }
  214. /* parse initial line */
  215. {
  216. char *line = evbuffer_readline( buf );
  217. int ret = _parse_init_line( request, line );
  218. free( line );
  219. if( ret != 0 )
  220. {
  221. free( request );
  222. return 0;
  223. }
  224. }
  225. /* create the header queue */
  226. request->headers = http_header_new();
  227. /* parse headers */
  228. {
  229. char *line = evbuffer_readline( buf ) ;
  230. int ret = 0;
  231. while( line != 0 && *line != '' ) /* there is one null line between header and body */
  232. {
  233. ret = http_add_header( request->headers, line );
  234. free( line );
  235. if( ret != 0 )
  236. {
  237. break;
  238. }
  239. line = evbuffer_readline( buf );
  240. }
  241. }
  242. /* ignore the bodies because it does not support now */
  243. return request;
  244. }
  245. void http_request_free( struct http_request *request )
  246. {
  247. free( request->uri );
  248. http_header_free( request->headers );
  249. free( request );
  250. }
  251. /**
  252.   currently, this function mainly to handle the http request, until now it only 
  253.   load the resource file and send them to the client.
  254. */
  255. int http_handle_request( struct evbuffer *buf, const struct http_request *request, res_exist_cb cb_exist, res_load_cb cb_load   )
  256. {
  257. int ret;
  258. /* check whether the request is valid */
  259. ret = _check_request_valid( buf, request );
  260. if( ret == -1 )
  261. {
  262. return -1;
  263. }
  264. ret = cb_exist( request->uri );
  265. if( ret < 0 )
  266. {
  267. /* file not found */
  268. char more_info[256];
  269. sprintf( more_info, "The resource : %s is not found on this sever!", request->uri );
  270. http_response_error( buf, HTTP_NOTFOUND, CODE_STR( HTTP_NOTFOUND ), more_info );
  271. return -1;
  272. }
  273. /* 200 OK */
  274. evbuffer_add_printf( buf, "HTTP/%d.%d %d %srn", request->ver.major, request->ver.minor, HTTP_OK, CODE_STR( HTTP_OK ) );
  275. /* add server info header */
  276. evbuffer_add_printf( buf, "Server: klhttpd/0.1.0rn" );
  277. /* add time header */
  278. _add_time_header( buf );
  279. /* add Content-Type header */
  280. {
  281. char mime[32];
  282. evbuffer_add_printf( buf, "Content-Type: %srn", _get_mime_type( request->uri, mime ) );
  283. }
  284. /* add Content-Length header */
  285. evbuffer_add_printf( buf, "Content-Length: %drn", ret );
  286. /* end of headers */
  287. evbuffer_add( buf, "rn", 2 );
  288. if( request->type == HTTP_GET )
  289. {
  290. /* load the resource */
  291. ret = cb_load( request->uri, buf );
  292. if( ret < 0 )
  293. {
  294. /* server unknown error */
  295. }
  296. }
  297. return 0;
  298. }
  299. void http_response_error( struct evbuffer *buf, int status, const char *status_str, const char *more_info )
  300. {
  301. #define ERR_FORMAT "<HTML><HEAD>n" 
  302.     "<TITLE>%d %s</TITLE>n" 
  303.     "</HEAD><BODY>n" 
  304.     "<H1>%d %s</H1>n" 
  305.     "%s<P>n" 
  306.     "</BODY></HTML>n"
  307. char content[512];
  308. size_t len;
  309. sprintf( content, ERR_FORMAT, status, status_str, status, status_str, more_info );
  310. len = strlen( content );
  311. /* initial line */
  312. evbuffer_add_printf( buf, "HTTP/1.1 %d %srn", status, status_str );
  313. /* add server info header */
  314. evbuffer_add_printf( buf, "Server: klhttpd/0.1.0rn" );
  315. /* add time header */
  316. _add_time_header( buf );
  317. /* content type */
  318. evbuffer_add_printf( buf, "Content-Type: text/htmlrn" );
  319. /* content length */
  320. evbuffer_add_printf( buf, "Content-Length: %drn", len );
  321. /* end of headers */
  322. evbuffer_add( buf, "rn", 2 );
  323. /* body */
  324. evbuffer_add( buf, content, len );
  325. #undef ERR_FORMAT
  326. }