You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

http.c 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #include "proto.h"
  2. #include "old_tcp.h"
  3. #include "url.h"
  4. #include "etherboot.h"
  5. /* The block size is currently chosen to be 512 bytes. This means, we can
  6. allocate the receive buffer on the stack, but it results in a noticeable
  7. performance penalty.
  8. This is what needs to be done in order to increase the block size:
  9. - size negotiation needs to be implemented in TCP
  10. - the buffer needs to be allocated on the heap
  11. - path MTU discovery needs to be implemented
  12. */ /***/ /* FIXME */
  13. #define BLOCKSIZE TFTP_DEFAULTSIZE_PACKET
  14. /**************************************************************************
  15. SEND_TCP_CALLBACK - Send data using TCP
  16. **************************************************************************/
  17. struct send_recv_state {
  18. struct buffer *recv_buffer;
  19. char *send_buffer;
  20. int send_length;
  21. int bytes_sent;
  22. int bytes_received;
  23. enum { RESULT_CODE, HEADER, DATA, ERROR, MOVED } recv_state;
  24. int rc;
  25. char *url;
  26. };
  27. static int send_tcp_request(int length, void *buffer, void *ptr) {
  28. struct send_recv_state *state = (struct send_recv_state *)ptr;
  29. if (length > state->send_length - state->bytes_sent)
  30. length = state->send_length - state->bytes_sent;
  31. memcpy(buffer, state->send_buffer + state->bytes_sent, length);
  32. state->bytes_sent += length;
  33. return (length);
  34. }
  35. /**************************************************************************
  36. RECV_TCP_CALLBACK - Receive data using TCP
  37. **************************************************************************/
  38. static int recv_tcp_request(int length, const void *data, void *ptr) {
  39. struct send_recv_state *state = (struct send_recv_state *)ptr;
  40. const char *buffer = data;
  41. /* Assume that the lines in an HTTP header do not straddle a packet */
  42. /* boundary. This is probably a reasonable assumption */
  43. if (state->recv_state == RESULT_CODE) {
  44. while (length > 0) {
  45. /* Find HTTP result code */
  46. if (*buffer == ' ') {
  47. const char *ptr = buffer + 1;
  48. int rc = strtoul(ptr, &ptr, 10);
  49. if (ptr >= buffer + length) {
  50. state->recv_state = ERROR;
  51. DBG ( "HTTP got bad result code\n" );
  52. return 0;
  53. }
  54. state->rc = rc;
  55. state->recv_state = HEADER;
  56. DBG ( "HTTP got result code %d\n", rc );
  57. goto header;
  58. }
  59. ++buffer;
  60. length--;
  61. }
  62. state->recv_state = ERROR;
  63. DBG ( "HTTP got no result code\n" );
  64. return 0;
  65. }
  66. if (state->recv_state == HEADER) {
  67. header: while (length > 0) {
  68. /* Check for HTTP redirect */
  69. if (state->rc >= 300 && state->rc < 400 &&
  70. !memcmp(buffer, "Location: ", 10)) {
  71. char *p;
  72. state->url = p = ( char * ) buffer + 10;
  73. while ( *p > ' ' ) {
  74. p++;
  75. }
  76. *p = '\0';
  77. state->recv_state = MOVED;
  78. DBG ( "HTTP got redirect to %s\n",
  79. state->url );
  80. return 1;
  81. }
  82. /* Find beginning of line */
  83. while (length > 0) {
  84. length--;
  85. if (*buffer++ == '\n')
  86. break;
  87. }
  88. /* Check for end of header */
  89. if (length >= 2 && !memcmp(buffer, "\r\n", 2)) {
  90. state->recv_state = DATA;
  91. buffer += 2;
  92. length -= 2;
  93. break;
  94. }
  95. }
  96. }
  97. if (state->recv_state == DATA) {
  98. DBG2 ( "HTTP received %d bytes\n", length );
  99. if ( ! fill_buffer ( state->recv_buffer, buffer,
  100. state->bytes_received, length ) )
  101. return 0;
  102. state->bytes_received += length;
  103. }
  104. return 1;
  105. }
  106. /**************************************************************************
  107. HTTP_GET - Get data using HTTP
  108. **************************************************************************/
  109. static int http ( char *url, struct sockaddr_in *server __unused,
  110. char *file __unused, struct buffer *buffer ) {
  111. struct protocol *proto;
  112. struct sockaddr_in http_server = *server;
  113. char *filename;
  114. static const char GET[] = "GET /%s HTTP/1.0\r\n\r\n";
  115. struct send_recv_state state;
  116. int length;
  117. state.rc = -1;
  118. state.url = url;
  119. state.recv_buffer = buffer;
  120. while ( 1 ) {
  121. length = strlen ( filename ) + strlen ( GET );
  122. {
  123. char send_buf[length];
  124. sprintf ( send_buf, GET, filename );
  125. state.send_buffer = send_buf;
  126. state.send_length = strlen ( send_buf );
  127. state.bytes_sent = 0;
  128. state.bytes_received = 0;
  129. state.recv_state = RESULT_CODE;
  130. tcp_transaction ( server->sin_addr.s_addr,
  131. server->sin_port, &state,
  132. send_tcp_request, (int (*)(int, const void *, void *))recv_tcp_request );
  133. }
  134. if ( state.recv_state == MOVED ) {
  135. if ( ! parse_url ( state.url, &proto,
  136. &http_server, &filename ) ) {
  137. printf ( "Invalid redirect URL %s\n",
  138. state.url );
  139. return 0;
  140. }
  141. continue;
  142. }
  143. break;
  144. }
  145. if ( state.rc != 200 ) {
  146. printf ( "Failed to download %s (rc = %d)\n",
  147. state.url, state.rc );
  148. return 0;
  149. }
  150. return 1;
  151. }
  152. static struct protocol http_protocol __protocol = {
  153. .name = "http",
  154. .default_port = 80,
  155. .load = http,
  156. };