Port of LwIP performed by Ralf in 2010. Not recommended for use with recent mbed libraries, but good demos of raw LwIP possible

Dependents:   LwIP_raw_API_serverExample tiny-dtls

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPClient.cpp Source File

HTTPClient.cpp

00001 #include "HTTPClient.h"
00002 #include "NetServer.h"
00003 #include "iputil.h"
00004 
00005 using namespace mbed;
00006 using namespace std;
00007 
00008 #define POST   0x1
00009 #define FDATA  0x2
00010 #define FRES   0x4
00011 #define GET    0x0
00012 #define CDATA  0x0
00013 #define CRES   0x0
00014 
00015 long fleft(FILE *fd) {
00016   long len, cur;
00017   cur = ftell(fd);
00018   fseek(fd, 0, SEEK_END);
00019   len = ftell(fd);
00020   fseek(fd, cur, SEEK_SET);
00021   return len;
00022 }
00023 
00024 
00025 HTTPClient::HTTPClient(const char *hostname, struct ip_addr ip, struct ip_addr nm, struct ip_addr gw, struct ip_addr dns)
00026   : TCPConnection(),  _auth(NULL), _timeout(0), _data(NULL), _headerfields(NULL), _timeout_max(60000) {
00027   NetServer *net = NULL;
00028   if(ip.addr != ip_addr_any.addr && nm.addr != ip_addr_any.addr && gw.addr != ip_addr_any.addr) {
00029     net = NetServer::create(ip, nm, gw);
00030     if(dns.addr != ip_addr_any.addr) {
00031       net->setDNS1(dns);
00032     }
00033   } else if(hostname) {
00034     net = NetServer::create();
00035   }
00036   if(hostname) {
00037     net->setHostname(hostname);
00038   }
00039 }
00040 
00041 void HTTPClient::timeout(int value) {
00042   _timeout_max = value;
00043 }
00044 
00045 void HTTPClient::err(err_t err) {
00046   release_callbacks();
00047 }
00048 
00049 err_t HTTPClient::poll() {
00050   if(NetServer::time() - _timeout > _timeout_max) {
00051     release_callbacks();
00052     close();
00053     printf("TIMEOUT\n");
00054     _ready = true;
00055     _state = 99;
00056   }
00057   return ERR_OK;
00058 }
00059 
00060 void HTTPClient::dnsreply(const char *hostname, struct ip_addr *ipaddr) {
00061   _ready = true;
00062   _ipaddr = *ipaddr;
00063   _state = (ipaddr==NULL)? 99 : 0;
00064   _timeout = NetServer::time();
00065 }
00066 
00067 err_t HTTPClient::connected(err_t err) {
00068   TCPConnection::connected(err);
00069   _ready = false;
00070   _state = 0;
00071   _resultoff = 0;
00072   if(_mode&POST) {
00073     write((void *)"POST ", 5,  TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
00074   } else {
00075     write((void *)"GET ", 4, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
00076   }
00077   if(strlen(_path) == 0) {
00078     write((void *)"/", 1, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
00079   } else {
00080     write((void *)_path, strlen(_path), TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
00081   }
00082   write((void *)" HTTP/1.1\r\nHost: ", 17, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
00083   write((void *)_host, _hostlen, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
00084   if(_auth&&(*_auth!='\0')) {
00085     write((void *)"\r\nAuthorization: Basic ", 23, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE); 
00086     write((void *)_auth, strlen(_auth), TCP_WRITE_FLAG_COPY |TCP_WRITE_FLAG_MORE); 
00087   }
00088   if(_headerfields&&(*_headerfields!='\0')) {
00089     write((void *)"\r\n", 2, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE); 
00090     write((void *)_headerfields, strlen(_headerfields), TCP_WRITE_FLAG_COPY |TCP_WRITE_FLAG_MORE); 
00091   }
00092   write((void *)"\r\nConnection: Close\r\n", 21, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_COPY); 
00093   if(_data) {
00094     char clen[256];
00095     int len, blen;
00096     if(_mode&FDATA) {
00097       //printf("Send file\n");
00098       len = fleft((FILE *)_data);
00099       sprintf(clen, "Content-Length: %d\r\n\r\n\0", len);
00100       write((void *)clen, strlen(clen), TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_COPY); 
00101       if(len) {
00102         do {
00103           int sb = sndbuf();
00104           blen = fread(clen, sizeof(char), (int)min(sb, 100), (FILE *)_data);
00105           write(clen, blen, (TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE));
00106           len -= blen;
00107         } while(len > 1 && blen);  
00108       }
00109     } else {
00110       len = strlen((const char *)_data);
00111       sprintf(clen, "Content-Length: %d\r\n\r\n\0", len);
00112       write((void *)clen, strlen(clen), TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_COPY); 
00113       write((void *)_data, len, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE); 
00114     }
00115   }
00116   write((void *)"\r\n", 2, TCP_WRITE_FLAG_COPY);
00117   _timeout = NetServer::time(); 
00118   return ERR_OK; 
00119 }
00120 
00121 #define _min(x, y) (((x)<(y))?(x):(y))
00122 err_t HTTPClient::recv(struct pbuf *p, err_t err) {
00123   if(err == ERR_OK && p != NULL&&_state<10) {
00124     _timeout = NetServer::time();
00125     struct pbuf *q = p;
00126     char *d = (char *)q->payload;
00127     recved(p->tot_len);
00128 
00129     while(q&&_state<10) {
00130       unsigned int end = ((unsigned int)(q->payload)+(unsigned int)(q->len));
00131       switch(_state) {
00132         case 0: {
00133           for(; _state==0 && ((unsigned int)d < end); d++) {
00134             if((*((char *)(d-0))=='\n')&&(*((char *)(d-1))=='\r')&&
00135                (*((char *)(d-2))=='\n')&&(*((char *)(d-3))=='\r')) {
00136               _state = 1;
00137               d += 1;
00138               break;
00139             }
00140           }
00141         } break;
00142         case 1: {
00143           if(_result) {
00144             if(_mode&FRES) {
00145               fwrite(d, sizeof(char), end - (unsigned int)d, (FILE *)_result);
00146               _resultoff  += (end - (unsigned int)d);
00147               d = (char *)end;
00148             } else {
00149               unsigned int len = _min(_resultleft, (end-(unsigned int)d));
00150               memcpy((char *)_result + _resultoff, d, len);
00151               _resultleft -= len;
00152               _resultoff  += len;
00153               d += len;
00154   
00155               if(!_resultleft) {
00156                 _state = 10;
00157               }
00158             }
00159           } else {
00160              _state = 10;
00161           }
00162         } break;
00163         default: {
00164           break;
00165         }
00166       }
00167       if(_state<10&&(unsigned int)d==end) {
00168         q = q->next;
00169         if(q) {
00170           d = static_cast<char *>(q->payload);
00171         }
00172       }
00173     }
00174   }
00175   
00176   if(p!=NULL) {
00177     pbuf_free(p);
00178   }
00179   
00180   if(_state>10||p==NULL||err!=ERR_OK) {
00181     release_callbacks();
00182     close();
00183     _ready = true;
00184   }
00185   return ERR_OK;
00186 }
00187 
00188 unsigned int HTTPClient::make(const char *request) {
00189   _request    = request;
00190   _resultoff  = 0;
00191   _ready      = false;
00192   _state      = 0;
00193   _hostlen    = 0;
00194   _port       = 0;
00195   _timeout    = NetServer::time();
00196   NetServer::ready();
00197 
00198   int hostlen = 0;
00199   if(strlen(_request)<10||strncmp("http://", _request, 7)!=0) {
00200     printf("Only http requests are allowed\n");
00201     return 0;
00202   }
00203   _path = _host = _request + 6;
00204   _host++;
00205   while(!_state == 1) {
00206     switch(*(++_path)) {
00207       case ':':
00208         _port = atoi(_path+1);
00209         break;
00210       case '/':
00211       case '\0':
00212         _port = (_port)?_port:80;
00213         _state  = 1;
00214         break;
00215       default:
00216         break;
00217     }
00218     if(!_port) {
00219       hostlen++;
00220     }
00221     if(!_state == 1) {
00222       _hostlen++;
00223     }
00224   }
00225   _state = 0;
00226   
00227   if(hostlen>256) {
00228     printf("Hostname longer than allowed\n");
00229     return 0;
00230   }
00231   
00232   char host[257];
00233   memcpy(host, _host, hostlen);
00234   host[hostlen] = 0;
00235   _timeout = NetServer::time();
00236   struct in_addr in;
00237   if(!inet_aton(host, &in)) {
00238     _ready = false;
00239     if(dnsrequest(host, &_ipaddr)==ERR_INPROGRESS) {
00240       while(!_ready) {
00241         NetServer::poll();
00242         wait_ms(10);
00243       }
00244       if(_state==99) {
00245         printf("Server not found\n");
00246         return 0;
00247       }
00248     }
00249   } else {
00250     _ipaddr.addr = in.s_addr;
00251   }
00252 
00253   _ready = false;
00254   _timeout = NetServer::time();
00255   connect();
00256   set_poll_interval(10);
00257   tcp_setprio(_pcb, TCP_PRIO_MIN);
00258   while(!_ready) {
00259     NetServer::poll();
00260     wait_ms(10);
00261   }
00262   //release_callbacks();
00263   close();
00264   if(_state==99) {
00265     printf("Connection error\n");
00266     return 0;
00267   }  
00268   
00269   if(!_mode&FRES&&_result) {
00270     ((char *)_result)[_resultoff+1]  = '\0';
00271   }
00272   return ((!_mode&FRES)&&!_result)?1:_resultoff;
00273   
00274 }
00275 
00276 void HTTPClient::auth(const char *user, const char *password) {
00277   if(user) {
00278     char up[256];
00279     sprintf(up, "%s:%s", user, password);
00280     _auth = new char[base64enc_len(up)+1];
00281     base64enc(up, strlen(up), _auth);
00282   } else if(_auth) {
00283     delete _auth;
00284     _auth = NULL;
00285   }
00286 }
00287 
00288 void HTTPClient::headers(const char *fields) {
00289   _headerfields = fields;
00290 }
00291 
00292 unsigned int HTTPClient::get(const char *url, char *result, int rsize) {
00293   _mode = GET | CDATA | CRES;
00294   _data = (void *)NULL;
00295   _result = (void *)result;
00296   _resultleft = rsize -1;
00297 
00298   return make(url);
00299 }
00300 
00301 unsigned int HTTPClient::get(const char *url, FILE *result) {
00302   _mode = GET | CDATA | FRES;
00303   _data = (void *)NULL;
00304   _result = (void *)result;
00305   _resultleft = 0;
00306 
00307   return make(url);
00308 }
00309 
00310 unsigned int HTTPClient::post(const char *url, const char *data, char *result, int rsize) {
00311   _mode = POST | CDATA | CRES;
00312   _data = (void *)data;
00313   _result = (void *)result;
00314   _resultleft = rsize -1;
00315   
00316   return make(url);
00317 }
00318 
00319 unsigned int HTTPClient::post(const char *url, const char *data, FILE *result) {
00320   _mode = POST | CDATA | FRES;
00321   _data = (void *)data;
00322   _result = (void *)result;
00323   _resultleft = 0;
00324   
00325   return make(url);
00326 }
00327 
00328 unsigned int HTTPClient::post(const char *url, FILE *data, FILE *result) {
00329   _mode = POST | FDATA | FRES;
00330   _data = (void *)data;
00331   _result = (void *)result;
00332   _resultleft = 0;
00333   
00334   return make(url);
00335 }
00336 
00337 unsigned int HTTPClient::post(const char *url, FILE *data, char *result, int rsize) {
00338   _mode = POST | FDATA | CRES;
00339   _data = (void *)data;
00340   _result = (void *)result;
00341   _resultleft = rsize -1;
00342   
00343   return make(url);
00344 }
00345