]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/net/http_client.c
47bb48051749762f148d78574ecc1804db9f55e6
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / net / http_client.c
1 //==========================================================================
2 //
3 //      net/http_client.c
4 //
5 //      Stand-alone HTTP support for RedBoot
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002, 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 // Date:         2002-05-22
47 // Purpose:      
48 // Description:  
49 //              
50 // This code is part of RedBoot (tm).
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 // HTTP client support
57
58 #include <redboot.h>     // have_net
59 #include <net/net.h>
60 #include <net/http.h>
61
62 // So we remember which ports have been used
63 static int get_port = 7800;
64
65 static struct _stream{
66     bool open;
67     int  avail, actual_len, pos, filelen;
68     char data[4096];
69     char *bufp;
70     tcp_socket_t sock;
71 } http_stream;
72
73 static __inline__ int
74 min(int a, int b)
75 {
76     if (a < b) 
77         return a;
78     else
79         return b;
80 }
81
82 int
83 http_stream_open(connection_info_t *info, int *err)
84 {
85     int res;
86     struct _stream *s = &http_stream;
87
88     if (!info->server->sin_port)
89         info->server->sin_port = 80;  // HTTP port
90     if ((res = __tcp_open(&s->sock, info->server, get_port++, 5000, err)) < 0) {
91         *err = HTTP_OPEN;
92         return -1;
93     }
94     diag_sprintf(s->data, "GET %s HTTP/1.0\r\n\r\n", info->filename);
95     __tcp_write_block(&s->sock, s->data, strlen(s->data));    
96     s->avail = 0;
97     s->open = true;
98     s->pos = 0;
99     return 0;
100 }
101
102 void
103 http_stream_close(int *err)
104 {    
105     struct _stream *s = &http_stream;
106
107     if (s->open) {
108         __tcp_abort(&s->sock,1);
109         s->open = false;    
110     }
111 }
112
113 int
114 http_stream_read(char *buf,
115                  int len,
116                  int *err)
117 {    
118     struct _stream *s = &http_stream;
119     int total = 0;
120     int cnt, code;
121
122     if (!s->open) {
123         return -1;  // Shouldn't happen, but...
124     }
125     while (len) {
126         while (s->avail == 0) {
127             // Need to wait for some data to arrive
128             __tcp_poll();
129             if (s->sock.state != _ESTABLISHED) {
130                 if (s->sock.state == _CLOSE_WAIT) {
131                     // This connection is breaking
132                     if (s->sock.data_bytes == 0 && s->sock.rxcnt == 0) {
133                         __tcp_close(&s->sock);
134                         return total;
135                     }  
136                 } else if (s->sock.state == _CLOSED) {
137                         // The connection is gone
138                         s->open = false;
139                         return -1;
140                 } else {        
141                     *err = HTTP_IO;
142                     return -1;
143                 }
144             }
145             s->actual_len = __tcp_read(&s->sock, s->data, sizeof(s->data));
146             if (s->actual_len > 0) {
147                 s->bufp = s->data;
148                 s->avail = s->actual_len;
149                 if (s->pos == 0) {
150                     // First data - need to scan HTTP response header
151                     if (strncmp(s->bufp, "HTTP/", 5) == 0) {
152                         // Should look like "HTTP/1.1 200 OK"
153                         s->bufp += 5;
154                         s->avail -= 5;
155                         // Find first space
156                         while ((s->avail > 0) && (*s->bufp != ' ')) {
157                             s->bufp++;  
158                             s->avail--;
159                         }
160                         // Now the integer response
161                         code = 0;
162                         while ((s->avail > 0) && (*s->bufp == ' ')) {
163                             s->bufp++;  
164                             s->avail--;
165                         }
166                         while ((s->avail > 0) && isdigit(*s->bufp)) {
167                             code = (code * 10) + (*s->bufp - '0');
168                             s->bufp++;  
169                             s->avail--;
170                         }
171                         // Make sure it says OK
172                         while ((s->avail > 0) && (*s->bufp == ' ')) {
173                             s->bufp++;  
174                             s->avail--;
175                         }
176                         if (strncmp(s->bufp, "OK", 2)) {
177                             switch (code) {
178                             case 400:
179                                 *err = HTTP_BADREQ;
180                                 break;
181                             case 404:
182                                 *err = HTTP_NOFILE;
183                                 break;
184                             default:
185                                 *err = HTTP_BADHDR;
186                                 break;
187                             }
188                             return -1;
189                         }
190                         // Find \r\n\r\n - end of HTTP preamble
191                         while (s->avail >= 4) {
192                             // This could be done faster, but not simpler
193                             if (strncmp(s->bufp, "\r\n\r\n", 4) == 0) {
194                                 s->bufp += 4;
195                                 s->avail -= 4;
196 #if 0 // DEBUG - show header
197                                 *(s->bufp-2) = '\0';
198                                 diag_printf(s->data);
199 #endif
200                                 break;
201                             }
202                             s->avail--;
203                             s->bufp++;
204                         }
205                         s->pos++;
206                     } else {
207                         // Unrecognized response
208                         *err = HTTP_BADHDR;
209                         return -1;
210                     }
211                 }
212             } else if (s->actual_len < 0) {
213                 *err = HTTP_IO;
214                 return -1;
215             }
216         }
217         cnt = min(len, s->avail);
218         memcpy(buf, s->bufp, cnt);
219         s->avail -= cnt;
220         s->bufp += cnt;
221         buf += cnt;
222         total += cnt;
223         len -= cnt;
224     }
225     return total;
226 }
227
228 char *
229 http_error(int err)
230 {
231     char *errmsg = "Unknown error";
232
233     switch (err) {
234     case HTTP_NOERR:
235         return "";
236     case HTTP_BADHDR:
237         return "Unrecognized HTTP response";
238     case HTTP_BADREQ:
239         return "Bad HTTP request (check file name)";
240     case HTTP_NOFILE:
241         return "No such file";
242     case HTTP_OPEN:
243         return "Can't connect to host";
244     case HTTP_IO:
245         return "I/O error";
246     }
247     return errmsg;
248 }
249
250 //
251 // RedBoot interface
252 //
253 GETC_IO_FUNCS(http_io, http_stream_open, http_stream_close,
254               0, http_stream_read, http_error);
255 RedBoot_load(http, http_io, true, true, 0);