|
@@ -1,7 +1,7 @@
|
|
1
|
+#include "proto.h"
|
|
2
|
+#include "tcp.h"
|
|
3
|
+#include "url.h"
|
1
|
4
|
#include "etherboot.h"
|
2
|
|
-#include "http.h"
|
3
|
|
-
|
4
|
|
-#ifdef DOWNLOAD_PROTO_HTTP
|
5
|
5
|
|
6
|
6
|
/* The block size is currently chosen to be 512 bytes. This means, we can
|
7
|
7
|
allocate the receive buffer on the stack, but it results in a noticeable
|
|
@@ -17,7 +17,9 @@
|
17
|
17
|
SEND_TCP_CALLBACK - Send data using TCP
|
18
|
18
|
**************************************************************************/
|
19
|
19
|
struct send_recv_state {
|
20
|
|
- int (*fnc)(unsigned char *data, int block, int len, int eof);
|
|
20
|
+ int ( * process ) ( unsigned char *data,
|
|
21
|
+ unsigned int blocknum,
|
|
22
|
+ unsigned int len, int eof );
|
21
|
23
|
char *send_buffer;
|
22
|
24
|
char *recv_buffer;
|
23
|
25
|
int send_length;
|
|
@@ -27,7 +29,7 @@ struct send_recv_state {
|
27
|
29
|
int bytes_received;
|
28
|
30
|
enum { RESULT_CODE, HEADER, DATA, ERROR, MOVED } recv_state;
|
29
|
31
|
int rc;
|
30
|
|
- char location[MAX_URL+1];
|
|
32
|
+ char *url;
|
31
|
33
|
};
|
32
|
34
|
|
33
|
35
|
static int send_tcp_request(int length, void *buffer, void *ptr) {
|
|
@@ -56,16 +58,19 @@ static int recv_tcp_request(int length, const void *buffer, void *ptr) {
|
56
|
58
|
int rc = strtoul(ptr, &ptr, 10);
|
57
|
59
|
if (ptr >= (const char *)buffer + length) {
|
58
|
60
|
state->recv_state = ERROR;
|
|
61
|
+ DBG ( "HTTP got bad result code\n" );
|
59
|
62
|
return 0;
|
60
|
63
|
}
|
61
|
64
|
state->rc = rc;
|
62
|
65
|
state->recv_state = HEADER;
|
|
66
|
+ DBG ( "HTTP got result code %d\n", rc );
|
63
|
67
|
goto header;
|
64
|
68
|
}
|
65
|
69
|
++(const char *)buffer;
|
66
|
70
|
length--;
|
67
|
71
|
}
|
68
|
72
|
state->recv_state = ERROR;
|
|
73
|
+ DBG ( "HTTP got no result code\n" );
|
69
|
74
|
return 0;
|
70
|
75
|
}
|
71
|
76
|
if (state->recv_state == HEADER) {
|
|
@@ -73,13 +78,16 @@ static int recv_tcp_request(int length, const void *buffer, void *ptr) {
|
73
|
78
|
/* Check for HTTP redirect */
|
74
|
79
|
if (state->rc >= 300 && state->rc < 400 &&
|
75
|
80
|
!memcmp(buffer, "Location: ", 10)) {
|
76
|
|
- char *ptr = state->location;
|
77
|
|
- int i;
|
78
|
|
- memcpy(ptr, buffer + 10, MAX_URL);
|
79
|
|
- for (i = 0; i < MAX_URL && *ptr > ' ';
|
80
|
|
- i++, ptr++);
|
81
|
|
- *ptr = '\000';
|
|
81
|
+ char *p;
|
|
82
|
+
|
|
83
|
+ state->url = p = ( char * ) buffer + 10;
|
|
84
|
+ while ( *p > ' ' ) {
|
|
85
|
+ p++;
|
|
86
|
+ }
|
|
87
|
+ *p = '\0';
|
82
|
88
|
state->recv_state = MOVED;
|
|
89
|
+ DBG ( "HTTP got redirect to %s\n",
|
|
90
|
+ state->url );
|
83
|
91
|
return 1;
|
84
|
92
|
}
|
85
|
93
|
/* Find beginning of line */
|
|
@@ -99,6 +107,7 @@ static int recv_tcp_request(int length, const void *buffer, void *ptr) {
|
99
|
107
|
}
|
100
|
108
|
if (state->recv_state == DATA) {
|
101
|
109
|
state->bytes_received += length;
|
|
110
|
+ DBG2 ( "HTTP received %d bytes\n", length );
|
102
|
111
|
while (length > 0) {
|
103
|
112
|
int copy_length = BLOCKSIZE - state->recv_length;
|
104
|
113
|
if (copy_length > length)
|
|
@@ -106,9 +115,11 @@ static int recv_tcp_request(int length, const void *buffer, void *ptr) {
|
106
|
115
|
memcpy(state->recv_buffer + state->recv_length,
|
107
|
116
|
buffer, copy_length);
|
108
|
117
|
if ((state->recv_length += copy_length) == BLOCKSIZE) {
|
109
|
|
- if (!state->fnc(state->recv_buffer,
|
110
|
|
- ++state->block, BLOCKSIZE, 0))
|
111
|
|
- return 0;
|
|
118
|
+ DBG2 ( "HTTP processing %d bytes\n",
|
|
119
|
+ BLOCKSIZE );
|
|
120
|
+ if (!state->process(state->recv_buffer,
|
|
121
|
+ ++state->block,
|
|
122
|
+ BLOCKSIZE, 0))
|
112
|
123
|
state->recv_length = 0;
|
113
|
124
|
}
|
114
|
125
|
length -= copy_length;
|
|
@@ -121,86 +132,70 @@ static int recv_tcp_request(int length, const void *buffer, void *ptr) {
|
121
|
132
|
/**************************************************************************
|
122
|
133
|
HTTP_GET - Get data using HTTP
|
123
|
134
|
**************************************************************************/
|
124
|
|
-int http(const char *url,
|
125
|
|
- int (*fnc)(unsigned char *, unsigned int, unsigned int, int)) {
|
|
135
|
+static int http ( char *url,
|
|
136
|
+ struct sockaddr_in *server __unused,
|
|
137
|
+ char *file __unused,
|
|
138
|
+ int ( * process ) ( unsigned char *data,
|
|
139
|
+ unsigned int blocknum,
|
|
140
|
+ unsigned int len, int eof ) ) {
|
|
141
|
+ struct protocol *proto;
|
|
142
|
+ struct sockaddr_in http_server = *server;
|
|
143
|
+ char *filename;
|
126
|
144
|
static const char GET[] = "GET /%s HTTP/1.0\r\n\r\n";
|
127
|
145
|
static char recv_buffer[BLOCKSIZE];
|
128
|
|
- in_addr destip;
|
129
|
|
- int port;
|
130
|
|
- int length;
|
131
|
146
|
struct send_recv_state state;
|
|
147
|
+ int length;
|
132
|
148
|
|
133
|
|
- state.fnc = fnc;
|
134
|
149
|
state.rc = -1;
|
135
|
150
|
state.block = 0;
|
136
|
151
|
state.recv_buffer = recv_buffer;
|
137
|
|
- length = strlen(url);
|
138
|
|
- if (length <= MAX_URL) {
|
139
|
|
- memcpy(state.location, url, length+1);
|
140
|
|
- destip = arptable[ARP_SERVER].ipaddr;
|
141
|
|
- port = url_port;
|
142
|
|
- if (port == -1)
|
143
|
|
- port = 80;
|
144
|
|
- goto first_time;
|
145
|
|
-
|
146
|
|
- do {
|
147
|
|
- state.rc = -1;
|
148
|
|
- state.block = 0;
|
149
|
|
- url = state.location;
|
150
|
|
- if (memcmp("http://", url, 7))
|
151
|
|
- break;
|
152
|
|
- url += 7;
|
153
|
|
- length = inet_aton(url, &destip);
|
154
|
|
- if (!length) {
|
155
|
|
- /* As we do not have support for DNS, assume*/
|
156
|
|
- /* that HTTP redirects always point to the */
|
157
|
|
- /* same machine */
|
158
|
|
- if (state.recv_state == MOVED) {
|
159
|
|
- while (*url &&
|
160
|
|
- *url != ':' && *url != '/') url++;
|
161
|
|
- } else {
|
162
|
|
- break;
|
163
|
|
- }
|
164
|
|
- }
|
165
|
|
- if (*(url += length) == ':') {
|
166
|
|
- port = strtoul(url, &url, 10);
|
167
|
|
- } else {
|
168
|
|
- port = 80;
|
169
|
|
- }
|
170
|
|
- if (!*url)
|
171
|
|
- url = "/";
|
172
|
|
- if (*url != '/')
|
173
|
|
- break;
|
174
|
|
- url++;
|
|
152
|
+ state.url = url;
|
|
153
|
+ state.process = process;
|
|
154
|
+ while ( 1 ) {
|
|
155
|
+ length = strlen ( filename ) + strlen ( GET );
|
|
156
|
+ {
|
|
157
|
+ char send_buf[length];
|
175
|
158
|
|
176
|
|
- first_time:
|
177
|
|
- length = strlen(url);
|
178
|
|
- state.send_length = sizeof(GET) - 3 + length;
|
179
|
|
-
|
180
|
|
- { char buf[state.send_length + 1];
|
181
|
|
- sprintf(state.send_buffer = buf, GET, url);
|
|
159
|
+ sprintf ( send_buf, GET, filename );
|
|
160
|
+ state.send_buffer = send_buf;
|
|
161
|
+ state.send_length = strlen ( send_buf );
|
182
|
162
|
state.bytes_sent = 0;
|
183
|
163
|
|
184
|
164
|
state.bytes_received = 0;
|
185
|
165
|
state.recv_state = RESULT_CODE;
|
186
|
166
|
|
187
|
167
|
state.recv_length = 0;
|
188
|
|
- tcp_transaction(destip.s_addr, 80, &state,
|
189
|
|
- send_tcp_request, recv_tcp_request);
|
|
168
|
+ tcp_transaction ( server->sin_addr.s_addr,
|
|
169
|
+ server->sin_port, &state,
|
|
170
|
+ send_tcp_request, recv_tcp_request );
|
|
171
|
+ }
|
|
172
|
+
|
|
173
|
+ if ( state.recv_state == MOVED ) {
|
|
174
|
+ if ( ! parse_url ( state.url, &proto,
|
|
175
|
+ &http_server, &filename ) ) {
|
|
176
|
+ printf ( "Invalid redirect URL %s\n",
|
|
177
|
+ state.url );
|
|
178
|
+ return 0;
|
190
|
179
|
}
|
191
|
|
- } while (state.recv_state == MOVED);
|
192
|
|
- } else {
|
193
|
|
- memcpy(state.location, url, MAX_URL);
|
194
|
|
- state.location[MAX_URL] = '\000';
|
|
180
|
+ continue;
|
|
181
|
+ }
|
|
182
|
+
|
|
183
|
+ break;
|
195
|
184
|
}
|
196
|
185
|
|
197
|
|
- if (state.rc == 200) {
|
198
|
|
- return fnc(recv_buffer, ++state.block, state.recv_length, 1);
|
|
186
|
+ if ( state.rc == 200 ) {
|
|
187
|
+ DBG2 ( "HTTP processing %d bytes\n", state.recv_length );
|
|
188
|
+ return process ( recv_buffer, ++state.block,
|
|
189
|
+ state.recv_length, 1 );
|
199
|
190
|
} else {
|
200
|
|
- printf("Failed to download %s (rc = %d)\n",
|
201
|
|
- state.location, state.rc);
|
|
191
|
+ printf ( "Failed to download %s (rc = %d)\n",
|
|
192
|
+ state.url, state.rc );
|
202
|
193
|
return 0;
|
203
|
194
|
}
|
204
|
195
|
}
|
205
|
196
|
|
206
|
|
-#endif /* DOWNLOAD_PROTO_HTTP */
|
|
197
|
+static struct protocol http_protocol __protocol = {
|
|
198
|
+ .name = "http",
|
|
199
|
+ .default_port = 80,
|
|
200
|
+ .load = http,
|
|
201
|
+};
|