hattori&ide

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TinyHTTP.cpp Source File

TinyHTTP.cpp

Go to the documentation of this file.
00001 /*
00002  * mbed Tiny HTTP Client
00003  * Copyright (c) 2011 Hiroshi Suga
00004  * Released under the MIT License: http://mbed.org/license/mit
00005  */
00006 
00007 /** @file
00008  * @brief Tiny HTTP Client
00009  */
00010 
00011 #include "mbed.h"
00012 #include "EthernetNetIf.h"
00013 #include "TCPSocket.h"
00014 #include "DNSRequest.h"
00015 #include "TinyHTTP.h"
00016 #include <ctype.h>
00017 
00018 
00019 TCPSocket *http;
00020 volatile int tcp_ready, tcp_readable, tcp_writable;
00021 volatile int dns_status;
00022 
00023 // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
00024 int base64enc(const char *input, unsigned int length, char *output, int len) {
00025   static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00026   unsigned int c, c1, c2, c3;
00027 
00028   if (len < ((((length-1)/3)+1)<<2)) return -1;
00029   for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) {
00030     c1 = ((((unsigned char)*((unsigned char *)&input[i]))));
00031     c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0;
00032     c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0;
00033 
00034     c = ((c1 & 0xFC) >> 2);
00035     output[j+0] = base64[c];
00036     c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4);
00037     output[j+1] = base64[c];
00038     c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6);
00039     output[j+2] = (length>i+1)?base64[c]:'=';
00040     c = (c3 & 0x3F);
00041     output[j+3] = (length>i+2)?base64[c]:'=';
00042   }
00043   output[(((length-1)/3)+1)<<2] = '\0';
00044   return 0;
00045 }
00046 
00047 // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
00048 int urlencode(char *str, char *buf, int len) {
00049   static const char to_hex[] = "0123456789ABCDEF";
00050  //  char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf;
00051   char *pstr = str, *pbuf = buf;
00052 
00053   if (len < (strlen(str) * 3 + 1)) return -1;
00054   while (*pstr) {
00055     if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') {
00056       *pbuf++ = *pstr;
00057     } else if (*pstr == ' ') {
00058       *pbuf++ = '+';
00059     } else {
00060       *pbuf++ = '%';
00061       *pbuf++ = to_hex[(*pstr >> 4) & 0x0f];
00062       *pbuf++ = to_hex[*pstr & 0x0f];
00063     }
00064     pstr++;
00065   }
00066   *pbuf = '\0';
00067   return 0;
00068 }
00069 
00070 
00071 void isr_http (TCPSocketEvent e) {
00072 
00073  #ifdef DEBUG
00074     printf("tcp(%d)\r\n", e);
00075  #endif
00076     switch(e) {
00077     case TCPSOCKET_CONNECTED:
00078         tcp_ready = 1;
00079         break;
00080 
00081     case TCPSOCKET_READABLE: //Incoming data
00082         tcp_readable = 1;
00083         break;
00084 
00085     case TCPSOCKET_WRITEABLE: //We can send data
00086         tcp_writable = 1;
00087         break;
00088 
00089     case TCPSOCKET_CONTIMEOUT:
00090     case TCPSOCKET_CONRST:
00091     case TCPSOCKET_CONABRT:
00092     case TCPSOCKET_ERROR:
00093     case TCPSOCKET_DISCONNECTED:
00094         tcp_ready = 0;
00095         break;
00096     }
00097 }
00098 
00099 void createauth (char *user, char *pwd, char *buf, int len) {
00100     char tmp[80];
00101 
00102     strncpy(buf, "Authorization: Basic ", len);
00103     snprintf(tmp, sizeof(tmp), "%s:%s", user, pwd);
00104     base64enc(tmp, strlen(tmp), &buf[strlen(buf)], len - strlen(buf));
00105     strncat(buf, "\r\n", len - strlen(buf));
00106 }
00107 
00108 void isr_dns (DNSReply r) {
00109 
00110  #ifdef DEBUG
00111     printf("dns(%d)\r\n", r);
00112  #endif
00113     if (DNS_FOUND) {
00114         dns_status = 1;
00115     } else {
00116         dns_status = -1;
00117     }
00118 }
00119 
00120 int httpRequest (int method, int sendTime, Host *host, char *uri, char *head, char *body) {
00121     TCPSocketErr err;
00122     Timer timeout;
00123     // int sendTime = 0;
00124     int sendTimeRemain = 0;
00125     char buf[100] = {0};
00126     int i, ret = -1;
00127 
00128     http = new TCPSocket;    // TCPsocektクラスのインスタンス生成
00129     tcp_ready = 0;
00130     tcp_readable = 0;
00131     tcp_writable = 0;
00132 
00133     http->setOnEvent(isr_http);
00134     // 関数ポインタでコールバックを設定する
00135     // 状態が変化すると毎回実行されるようになる?
00136 
00137     // connect
00138     // IPアドレスが入力されていない場合はDNSサーバーへアクセスしてIPアドレス取得
00139     if (host->getIp().isNull()) {
00140         // resolve
00141         DNSRequest dns;
00142         dns_status = 0;
00143         dns.setOnReply(isr_dns);
00144         if (dns.resolve(host) != DNS_OK) goto exit;
00145         timeout.reset();
00146         timeout.start();
00147         while (timeout.read_ms() < HTTP_TIMEOUT) {
00148             if (dns_status) break;
00149             Net::poll();
00150         }
00151         timeout.stop();
00152         if (dns_status <= 0) goto exit;
00153 #ifdef DEBUG
00154         printf("%s [%d.%d.%d.%d]\r\n", host->getName(), (unsigned char)host->getIp()[0], (unsigned char)host->getIp()[1], (unsigned char)host->getIp()[2], (unsigned char)host->getIp()[3]);
00155 #endif
00156     }
00157 
00158     if (! host->getPort()) {
00159         host->setPort(HTTP_PORT);  // ポート番号が設定されていない場合
00160     }
00161     err = http->connect(*host);
00162     if (err != TCPSOCKET_OK) goto exit;
00163 
00164     // wait connect
00165     timeout.reset();
00166     timeout.start();
00167     while (timeout.read_ms() < sendTime) {
00168         if (tcp_ready) break;
00169         Net::poll();
00170     }
00171     sendTimeRemain = sendTime - timeout.read_ms();
00172     timeout.stop();
00173     if (! tcp_ready) goto exit;
00174 
00175     // send request
00176     if (method == METHOD_POST) {
00177         http->send("POST ", 5);
00178     } else {
00179         http->send("GET ", 4);
00180     }
00181     http->send(uri, strlen(uri));
00182     http->send(" HTTP/1.1\r\nHost: ", 17);
00183     http->send(host->getName(), strlen(host->getName()));
00184     http->send("\r\n", 2);
00185     http->send("Connection: close\r\n", 19);
00186     if (head) {
00187         http->send(head, strlen(head));
00188     }
00189     if (method == METHOD_POST) {
00190         sprintf(buf, "Content-Length: %d\r\n", strlen(body));
00191         http->send(buf, strlen(buf));
00192     }
00193     http->send("\r\n", 2);
00194 
00195     // post method
00196     if (method == METHOD_POST && body) {
00197         http->send(body, strlen(body));
00198     }
00199 
00200     // wait responce
00201     timeout.reset();
00202     timeout.start();
00203     while (timeout.read_ms() < sendTimeRemain) {
00204         if (tcp_readable) break;
00205         Net::poll();
00206     }
00207     timeout.stop();
00208     if (! tcp_readable) goto exit;
00209 
00210     // recv responce
00211     i = http->recv(buf, sizeof(buf) - 1);
00212     buf[i] = 0;
00213     if (i < sizeof(buf) - 1) tcp_readable = 0;
00214     if (strncmp(buf, "HTTP/", 5) == 0) {
00215         ret = atoi(&buf[9]);
00216     }
00217 #ifdef DEBUG
00218     printf(buf);
00219 #endif
00220 
00221     // recv dummy
00222     timeout.reset();
00223     timeout.start();
00224     while (timeout.read_ms() < HTTP_TIMEOUT) {
00225         if (tcp_readable) {
00226             i = http->recv(buf, sizeof(buf) - 1);
00227             buf[i] = 0;
00228             if (i < sizeof(buf) - 1) tcp_readable = 0;
00229 #ifdef DEBUG
00230             printf(buf);
00231 #endif
00232             timeout.reset();
00233         } else
00234         if (! tcp_ready) {
00235             break;
00236         }
00237         Net::poll();
00238     }
00239     timeout.stop();
00240 
00241 exit:
00242     http->resetOnEvent();
00243     http->close();
00244     delete http;
00245 
00246     return ret;
00247 }