Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #include <stddef.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <vsprintf.h>
  5. #include <assert.h>
  6. #include <gpxe/async.h>
  7. #include <gpxe/http.h>
  8. /** @file
  9. *
  10. * The Hyper Text Transfer Protocol (HTTP)
  11. *
  12. * This file implements the TCP-based HTTP protocol. It connects to the
  13. * server specified in http_request::tcp and transmit an HTTP GET request
  14. * for the file specified in http_request::filename. It then decoded the
  15. * HTTP header, determining file status and file size. Then sends the file
  16. * to the callback function at http_request::callback().
  17. * **NOTE**: still working on correcting the closing of the tcp connection
  18. *
  19. * To use this code, do something like:
  20. *
  21. * @code
  22. *
  23. * static void my_callback ( struct http_request *http, char *data, size_t len ) {
  24. * ... process data ...
  25. * }
  26. *
  27. * struct http_request http = {
  28. * .filename = "path/to/file",
  29. * .callback = my_callback,
  30. * };
  31. *
  32. * ... assign http.tcp.server ...
  33. *
  34. * rc = async_wait ( get_http ( &http ) );
  35. *
  36. * @endcode
  37. *
  38. */
  39. static inline struct http_request *
  40. tcp_to_http ( struct tcp_application *app ) {
  41. return container_of ( app, struct http_request, tcp );
  42. }
  43. /**
  44. * Close an HTTP connection
  45. *
  46. * @v app a TCP Application
  47. * @v status connection status at close
  48. */
  49. static void http_closed ( struct tcp_application *app, int status ) {
  50. struct http_request *http = tcp_to_http ( app );
  51. async_done ( &http->aop, status );
  52. }
  53. /**
  54. * Callback after a TCP connection is established
  55. *
  56. * @v app a TCP Application
  57. */
  58. static void http_connected ( struct tcp_application *app ) {
  59. struct http_request *http = tcp_to_http ( app );
  60. http->state = HTTP_REQUEST_FILE;
  61. }
  62. /**
  63. * Callback for when TCP data is acknowledged
  64. *
  65. * @v app a TCP Application
  66. * @v len the length of data acked
  67. */
  68. static void http_acked ( struct tcp_application *app, size_t len __attribute__ ((unused)) ) {
  69. struct http_request *http = tcp_to_http ( app );
  70. // assume that the whole GET request was sent in on epacket
  71. switch ( http->state ) {
  72. case HTTP_REQUEST_FILE:
  73. http->state = HTTP_PARSE_HEADER;
  74. break;
  75. case HTTP_PARSE_HEADER:
  76. case HTTP_RECV_FILE:
  77. break;
  78. case HTTP_DONE:
  79. //tcp_close(app);
  80. break;
  81. default:
  82. break;
  83. }
  84. //printf("acked\n");
  85. }
  86. /**
  87. * Callback when new TCP data is recieved
  88. *
  89. * @v app a TCP Application
  90. * @v data a pointer to the data recieved
  91. * @v len length of data buffer
  92. */
  93. static void http_newdata ( struct tcp_application *app, void *data,
  94. size_t len ) {
  95. struct http_request *http = tcp_to_http ( app );
  96. char *content_length;
  97. char *start = data;
  98. char *rcp; int rc;
  99. switch ( http->state ) {
  100. case HTTP_PARSE_HEADER:
  101. if(strncmp("HTTP/",data,5) != 0){
  102. // no http header
  103. printf("Error: no HTTP Header\n");
  104. }
  105. // if rc is not 200, then handle problem
  106. // either redirect or not there
  107. rcp = strstr(data,"HTTP");
  108. if(rcp == NULL){ printf("Could not find header status line.\n"); }
  109. rcp += 9;
  110. rc = strtoul(rcp,NULL,10);
  111. printf("RC=%d\n",rc);
  112. content_length = strstr(data,"Content-Length: ");
  113. if(content_length != NULL){
  114. content_length += 16;
  115. http->file_size = strtoul(content_length,NULL,10);
  116. http->file_recv = 0;
  117. printf("http->file_size = %d\n", http->file_size);
  118. }
  119. start = strstr(data,"\r\n\r\n");
  120. if(start == NULL){ printf("No end of header\n"); }
  121. else{
  122. start += 4;
  123. len -= ((void *)start - data);
  124. http->state = HTTP_RECV_FILE;
  125. }
  126. if ( http->state != HTTP_RECV_FILE )
  127. break;
  128. case HTTP_RECV_FILE:
  129. http->callback(http,start,len);
  130. //http->file_size -= len;
  131. //printf("File recv is %d\n", http->file_recv);
  132. if ( http->file_recv == http->file_size ){
  133. http->state = HTTP_DONE;
  134. tcp_close(app);
  135. }
  136. break;
  137. case HTTP_REQUEST_FILE:
  138. case HTTP_DONE:
  139. default:
  140. break;
  141. }
  142. }
  143. /**
  144. * Callback for sending TCP data
  145. *
  146. * @v app a TCP Application
  147. */
  148. static void http_senddata ( struct tcp_application *app, void *buf, size_t len ) {
  149. struct http_request *http = tcp_to_http ( app );
  150. switch ( http->state ){
  151. case HTTP_REQUEST_FILE:
  152. len = snprintf(buf,len,"GET %s HTTP/1.0\r\n\r\n",http->filename);
  153. printf("%s\n",(char *)buf);
  154. // string is: GET <file> HTTP/1.0\r\n\r\n
  155. tcp_send ( app, buf, len);
  156. break;
  157. case HTTP_PARSE_HEADER:
  158. case HTTP_RECV_FILE:
  159. break;
  160. case HTTP_DONE:
  161. //tcp_close(app)
  162. break;
  163. default:
  164. break;
  165. }
  166. }
  167. static struct tcp_operations http_tcp_operations = {
  168. .closed = http_closed,
  169. .connected = http_connected,
  170. .acked = http_acked,
  171. .newdata = http_newdata,
  172. .senddata = http_senddata,
  173. };
  174. /**
  175. * Initiate a HTTP connection
  176. *
  177. * @v http a HTTP request
  178. */
  179. struct async_operation * get_http ( struct http_request *http ) {
  180. int rc;
  181. http->tcp.tcp_op = &http_tcp_operations;
  182. http->state = HTTP_REQUEST_FILE;
  183. if ( ( rc = tcp_connect ( &http->tcp, &http->server, 0 ) ) != 0 )
  184. async_done ( &http->aop, rc );
  185. return &http->aop;
  186. }