apps/webclient/webclient.c

Go to the documentation of this file.
00001 /**
00002  * \addtogroup apps
00003  * @{
00004  */
00005 
00006 /**
00007  * \defgroup webclient Web client
00008  * @{
00009  *
00010  * This example shows a HTTP client that is able to download web pages
00011  * and files from web servers. It requires a number of callback
00012  * functions to be implemented by the module that utilizes the code:
00013  * webclient_datahandler(), webclient_connected(),
00014  * webclient_timedout(), webclient_aborted(), webclient_closed().
00015  */
00016 
00017 /**
00018  * \file
00019  * Implementation of the HTTP client.
00020  * \author Adam Dunkels <adam@dunkels.com>
00021  */
00022 
00023 /*
00024  * Copyright (c) 2002, Adam Dunkels.
00025  * All rights reserved.
00026  *
00027  * Redistribution and use in source and binary forms, with or without
00028  * modification, are permitted provided that the following conditions
00029  * are met:
00030  * 1. Redistributions of source code must retain the above copyright
00031  *    notice, this list of conditions and the following disclaimer.
00032  * 2. Redistributions in binary form must reproduce the above
00033  *    copyright notice, this list of conditions and the following
00034  *    disclaimer in the documentation and/or other materials provided
00035  *    with the distribution.
00036  * 3. The name of the author may not be used to endorse or promote
00037  *    products derived from this software without specific prior
00038  *    written permission.
00039  *
00040  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
00041  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00042  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00043  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00044  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00045  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00046  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00047  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00048  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00049  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00050  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00051  *
00052  * This file is part of the uIP TCP/IP stack.
00053  *
00054  * $Id: webclient.c,v 1.2 2006/06/11 21:46:37 adam Exp $
00055  *
00056  */
00057 
00058 #include "uip.h"
00059 #include "uiplib.h"
00060 #include "webclient.h"
00061 #include "resolv.h"
00062 
00063 #include <string.h>
00064 
00065 #define WEBCLIENT_TIMEOUT 100
00066 
00067 #define WEBCLIENT_STATE_STATUSLINE 0
00068 #define WEBCLIENT_STATE_HEADERS    1
00069 #define WEBCLIENT_STATE_DATA       2
00070 #define WEBCLIENT_STATE_CLOSE      3
00071 
00072 #define HTTPFLAG_NONE   0
00073 #define HTTPFLAG_OK     1
00074 #define HTTPFLAG_MOVED  2
00075 #define HTTPFLAG_ERROR  3
00076 
00077 
00078 #define ISO_nl       0x0a
00079 #define ISO_cr       0x0d
00080 #define ISO_space    0x20
00081 
00082 
00083 static struct webclient_state s;
00084 
00085 /*-----------------------------------------------------------------------------------*/
00086 char *
00087 webclient_mimetype(void)
00088 {
00089   return s.mimetype;
00090 }
00091 /*-----------------------------------------------------------------------------------*/
00092 char *
00093 webclient_filename(void)
00094 {
00095   return s.file;
00096 }
00097 /*-----------------------------------------------------------------------------------*/
00098 char *
00099 webclient_hostname(void)
00100 {
00101   return s.host;
00102 }
00103 /*-----------------------------------------------------------------------------------*/
00104 unsigned short
00105 webclient_port(void)
00106 {
00107   return s.port;
00108 }
00109 /*-----------------------------------------------------------------------------------*/
00110 void
00111 webclient_init(void)
00112 {
00113 
00114 }
00115 /*-----------------------------------------------------------------------------------*/
00116 static void
00117 init_connection(void)
00118 {
00119   s.state = WEBCLIENT_STATE_STATUSLINE;
00120 
00121   s.getrequestleft = sizeof(http_get) - 1 + 1 +
00122     sizeof(http_10) - 1 +
00123     sizeof(http_crnl) - 1 +
00124     sizeof(http_host) - 1 +
00125     sizeof(http_crnl) - 1 +
00126     strlen(http_user_agent_fields) +
00127     strlen(s.file) + strlen(s.host);
00128   s.getrequestptr = 0;
00129 
00130   s.httpheaderlineptr = 0;
00131 }
00132 /*-----------------------------------------------------------------------------------*/
00133 void
00134 webclient_close(void)
00135 {
00136   s.state = WEBCLIENT_STATE_CLOSE;
00137 }
00138 /*-----------------------------------------------------------------------------------*/
00139 unsigned char
00140 webclient_get(char *host, u16_t port, char *file)
00141 {
00142   struct uip_conn *conn;
00143   uip_ipaddr_t *ipaddr;
00144   static uip_ipaddr_t addr;
00145   
00146   /* First check if the host is an IP address. */
00147   ipaddr = &addr;
00148   if(uiplib_ipaddrconv(host, (unsigned char *)addr) == 0) {
00149     ipaddr = (uip_ipaddr_t *)resolv_lookup(host);
00150     
00151     if(ipaddr == NULL) {
00152       return 0;
00153     }
00154   }
00155   
00156   conn = uip_connect(ipaddr, htons(port));
00157   
00158   if(conn == NULL) {
00159     return 0;
00160   }
00161   
00162   s.port = port;
00163   strncpy(s.file, file, sizeof(s.file));
00164   strncpy(s.host, host, sizeof(s.host));
00165   
00166   init_connection();
00167   return 1;
00168 }
00169 /*-----------------------------------------------------------------------------------*/
00170 static unsigned char *
00171 copy_string(unsigned char *dest,
00172             const unsigned char *src, unsigned char len)
00173 {
00174   strncpy(dest, src, len);
00175   return dest + len;
00176 }
00177 /*-----------------------------------------------------------------------------------*/
00178 static void
00179 senddata(void)
00180 {
00181   u16_t len;
00182   char *getrequest;
00183   char *cptr;
00184   
00185   if(s.getrequestleft > 0) {
00186     cptr = getrequest = (char *)uip_appdata;
00187 
00188     cptr = copy_string(cptr, http_get, sizeof(http_get) - 1);
00189     cptr = copy_string(cptr, s.file, strlen(s.file));
00190     *cptr++ = ISO_space;
00191     cptr = copy_string(cptr, http_10, sizeof(http_10) - 1);
00192 
00193     cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1);
00194     
00195     cptr = copy_string(cptr, http_host, sizeof(http_host) - 1);
00196     cptr = copy_string(cptr, s.host, strlen(s.host));
00197     cptr = copy_string(cptr, http_crnl, sizeof(http_crnl) - 1);
00198 
00199     cptr = copy_string(cptr, http_user_agent_fields,
00200                        strlen(http_user_agent_fields));
00201     
00202     len = s.getrequestleft > uip_mss()?
00203       uip_mss():
00204       s.getrequestleft;
00205     uip_send(&(getrequest[s.getrequestptr]), len);
00206   }
00207 }
00208 /*-----------------------------------------------------------------------------------*/
00209 static void
00210 acked(void)
00211 {
00212   u16_t len;
00213   
00214   if(s.getrequestleft > 0) {
00215     len = s.getrequestleft > uip_mss()?
00216       uip_mss():
00217       s.getrequestleft;
00218     s.getrequestleft -= len;
00219     s.getrequestptr += len;
00220   }
00221 }
00222 /*-----------------------------------------------------------------------------------*/
00223 static u16_t
00224 parse_statusline(u16_t len)
00225 {
00226   char *cptr;
00227   
00228   while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) {
00229     s.httpheaderline[s.httpheaderlineptr] = *(char *)uip_appdata;
00230     ++((char *)uip_appdata);
00231     --len;
00232     if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) {
00233 
00234       if((strncmp(s.httpheaderline, http_10,
00235                   sizeof(http_10) - 1) == 0) ||
00236          (strncmp(s.httpheaderline, http_11,
00237                   sizeof(http_11) - 1) == 0)) {
00238         cptr = &(s.httpheaderline[9]);
00239         s.httpflag = HTTPFLAG_NONE;
00240         if(strncmp(cptr, http_200, sizeof(http_200) - 1) == 0) {
00241           /* 200 OK */
00242           s.httpflag = HTTPFLAG_OK;
00243         } else if(strncmp(cptr, http_301, sizeof(http_301) - 1) == 0 ||
00244                   strncmp(cptr, http_302, sizeof(http_302) - 1) == 0) {
00245           /* 301 Moved permanently or 302 Found. Location: header line
00246              will contain thw new location. */
00247           s.httpflag = HTTPFLAG_MOVED;
00248         } else {
00249           s.httpheaderline[s.httpheaderlineptr - 1] = 0;
00250         }
00251       } else {
00252         uip_abort();
00253         webclient_aborted();
00254         return 0;
00255       }
00256       
00257       /* We're done parsing the status line, so we reset the pointer
00258          and start parsing the HTTP headers.*/
00259       s.httpheaderlineptr = 0;
00260       s.state = WEBCLIENT_STATE_HEADERS;
00261       break;
00262     } else {
00263       ++s.httpheaderlineptr;
00264     }
00265   }
00266   return len;
00267 }
00268 /*-----------------------------------------------------------------------------------*/
00269 static char
00270 casecmp(char *str1, const char *str2, char len)
00271 {
00272   static char c;
00273   
00274   while(len > 0) {
00275     c = *str1;
00276     /* Force lower-case characters. */
00277     if(c & 0x40) {
00278       c |= 0x20;
00279     }
00280     if(*str2 != c) {
00281       return 1;
00282     }
00283     ++str1;
00284     ++str2;
00285     --len;
00286   }
00287   return 0;
00288 }
00289 /*-----------------------------------------------------------------------------------*/
00290 static u16_t
00291 parse_headers(u16_t len)
00292 {
00293   char *cptr;
00294   static unsigned char i;
00295   
00296   while(len > 0 && s.httpheaderlineptr < sizeof(s.httpheaderline)) {
00297     s.httpheaderline[s.httpheaderlineptr] = *(char *)uip_appdata;
00298     ++((char *)uip_appdata);
00299     --len;
00300     if(s.httpheaderline[s.httpheaderlineptr] == ISO_nl) {
00301       /* We have an entire HTTP header line in s.httpheaderline, so
00302          we parse it. */
00303       if(s.httpheaderline[0] == ISO_cr) {
00304         /* This was the last header line (i.e., and empty "\r\n"), so
00305            we are done with the headers and proceed with the actual
00306            data. */
00307         s.state = WEBCLIENT_STATE_DATA;
00308         return len;
00309       }
00310 
00311       s.httpheaderline[s.httpheaderlineptr - 1] = 0;
00312       /* Check for specific HTTP header fields. */
00313       if(casecmp(s.httpheaderline, http_content_type,
00314                      sizeof(http_content_type) - 1) == 0) {
00315         /* Found Content-type field. */
00316         cptr = strchr(s.httpheaderline, ';');
00317         if(cptr != NULL) {
00318           *cptr = 0;
00319         }
00320         strncpy(s.mimetype, s.httpheaderline +
00321                 sizeof(http_content_type) - 1, sizeof(s.mimetype));
00322       } else if(casecmp(s.httpheaderline, http_location,
00323                             sizeof(http_location) - 1) == 0) {
00324         cptr = s.httpheaderline +
00325           sizeof(http_location) - 1;
00326         
00327         if(strncmp(cptr, http_http, 7) == 0) {
00328           cptr += 7;
00329           for(i = 0; i < s.httpheaderlineptr - 7; ++i) {
00330             if(*cptr == 0 ||
00331                *cptr == '/' ||
00332                *cptr == ' ' ||
00333                *cptr == ':') {
00334               s.host[i] = 0;
00335               break;
00336             }
00337             s.host[i] = *cptr;
00338             ++cptr;
00339           }
00340         }
00341         strncpy(s.file, cptr, sizeof(s.file));
00342         /*      s.file[s.httpheaderlineptr - i] = 0;*/
00343       }
00344 
00345 
00346       /* We're done parsing, so we reset the pointer and start the
00347          next line. */
00348       s.httpheaderlineptr = 0;
00349     } else {
00350       ++s.httpheaderlineptr;
00351     }
00352   }
00353   return len;
00354 }
00355 /*-----------------------------------------------------------------------------------*/
00356 static void
00357 newdata(void)
00358 {
00359   u16_t len;
00360 
00361   len = uip_datalen();
00362 
00363   if(s.state == WEBCLIENT_STATE_STATUSLINE) {
00364     len = parse_statusline(len);
00365   }
00366   
00367   if(s.state == WEBCLIENT_STATE_HEADERS && len > 0) {
00368     len = parse_headers(len);
00369   }
00370 
00371   if(len > 0 && s.state == WEBCLIENT_STATE_DATA &&
00372      s.httpflag != HTTPFLAG_MOVED) {
00373     webclient_datahandler((char *)uip_appdata, len);
00374   }
00375 }
00376 /*-----------------------------------------------------------------------------------*/
00377 void
00378 webclient_appcall(void)
00379 {
00380   if(uip_connected()) {
00381     s.timer = 0;
00382     s.state = WEBCLIENT_STATE_STATUSLINE;
00383     senddata();
00384     webclient_connected();
00385     return;
00386   }
00387 
00388   if(s.state == WEBCLIENT_STATE_CLOSE) {
00389     webclient_closed();
00390     uip_abort();
00391     return;
00392   }
00393 
00394   if(uip_aborted()) {
00395     webclient_aborted();
00396   }
00397   if(uip_timedout()) {
00398     webclient_timedout();
00399   }
00400 
00401   
00402   if(uip_acked()) {
00403     s.timer = 0;
00404     acked();
00405   }
00406   if(uip_newdata()) {
00407     s.timer = 0;
00408     newdata();
00409   }
00410   if(uip_rexmit() ||
00411      uip_newdata() ||
00412      uip_acked()) {
00413     senddata();
00414   } else if(uip_poll()) {
00415     ++s.timer;
00416     if(s.timer == WEBCLIENT_TIMEOUT) {
00417       webclient_timedout();
00418       uip_abort();
00419       return;
00420     }
00421         /*    senddata();*/
00422   }
00423 
00424   if(uip_closed()) {
00425     if(s.httpflag != HTTPFLAG_MOVED) {
00426       /* Send NULL data to signal EOF. */
00427       webclient_datahandler(NULL, 0);
00428     } else {
00429       if(resolv_lookup(s.host) == NULL) {
00430         resolv_query(s.host);
00431       }
00432       webclient_get(s.host, s.port, s.file);
00433     }
00434   }
00435 }
00436 /*-----------------------------------------------------------------------------------*/
00437 
00438 /** @} */
00439 /** @} */

Generated on Mon Jun 12 10:23:01 2006 for uIP 1.0 by  doxygen 1.4.6