source: SVN/cambria/redboot/packages/redboot/current/src/net/http_client.c @ 1

Last change on this file since 1 was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 8.2 KB
Line 
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
63static int get_port = 7800;
64
65static 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
73static __inline__ int
74min(int a, int b)
75{
76    if (a < b) 
77        return a;
78    else
79        return b;
80}
81
82int
83http_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
102void
103http_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
113int
114http_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
228char *
229http_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//
253GETC_IO_FUNCS(http_io, http_stream_open, http_stream_close,
254              0, http_stream_read, http_error);
255RedBoot_load(http, http_io, true, true, 0);
Note: See TracBrowser for help on using the repository browser.