For PETEY
Dependencies: mbed EthernetNetIf
TinyHTTP.cpp@1:9f15e579d914, 2011-07-27 (annotated)
- Committer:
- okini3939
- Date:
- Wed Jul 27 16:19:14 2011 +0000
- Revision:
- 1:9f15e579d914
- Parent:
- 0:f2bf5f966801
- Child:
- 2:764ecec3dc59
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
okini3939 | 0:f2bf5f966801 | 1 | /* |
okini3939 | 0:f2bf5f966801 | 2 | * mbed Tiny HTTP Client |
okini3939 | 0:f2bf5f966801 | 3 | * Copyright (c) 2011 Hiroshi Suga |
okini3939 | 0:f2bf5f966801 | 4 | * Released under the MIT License: http://mbed.org/license/mit |
okini3939 | 0:f2bf5f966801 | 5 | */ |
okini3939 | 0:f2bf5f966801 | 6 | |
okini3939 | 0:f2bf5f966801 | 7 | /** @file |
okini3939 | 0:f2bf5f966801 | 8 | * @brief Tiny HTTP Client |
okini3939 | 0:f2bf5f966801 | 9 | */ |
okini3939 | 0:f2bf5f966801 | 10 | |
okini3939 | 0:f2bf5f966801 | 11 | #include "mbed.h" |
okini3939 | 0:f2bf5f966801 | 12 | #include "EthernetNetIf.h" |
okini3939 | 0:f2bf5f966801 | 13 | #include "TCPSocket.h" |
okini3939 | 0:f2bf5f966801 | 14 | #include "DNSRequest.h" |
okini3939 | 0:f2bf5f966801 | 15 | #include "TinyHTTP.h" |
okini3939 | 0:f2bf5f966801 | 16 | |
okini3939 | 0:f2bf5f966801 | 17 | #define STATUS_NONE 0 |
okini3939 | 0:f2bf5f966801 | 18 | #define STATUS_READABLE 1 |
okini3939 | 0:f2bf5f966801 | 19 | #define STATUS_CONNECTED 2 |
okini3939 | 0:f2bf5f966801 | 20 | #define STATUS_ERROR 3 |
okini3939 | 0:f2bf5f966801 | 21 | #define STATUS_DISCONNECTED 4 |
okini3939 | 0:f2bf5f966801 | 22 | |
okini3939 | 0:f2bf5f966801 | 23 | |
okini3939 | 0:f2bf5f966801 | 24 | TCPSocket *http; |
okini3939 | 0:f2bf5f966801 | 25 | volatile int tcp_status = 0, dns_status = 0; |
okini3939 | 0:f2bf5f966801 | 26 | |
okini3939 | 0:f2bf5f966801 | 27 | // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) |
okini3939 | 0:f2bf5f966801 | 28 | void base64enc(const char *input, unsigned int length, char *output) { |
okini3939 | 0:f2bf5f966801 | 29 | static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
okini3939 | 0:f2bf5f966801 | 30 | unsigned int c, c1, c2, c3; |
okini3939 | 0:f2bf5f966801 | 31 | for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) { |
okini3939 | 0:f2bf5f966801 | 32 | c1 = ((((unsigned char)*((unsigned char *)&input[i])))); |
okini3939 | 0:f2bf5f966801 | 33 | c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0; |
okini3939 | 0:f2bf5f966801 | 34 | c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0; |
okini3939 | 0:f2bf5f966801 | 35 | |
okini3939 | 0:f2bf5f966801 | 36 | c = ((c1 & 0xFC) >> 2); |
okini3939 | 0:f2bf5f966801 | 37 | output[j+0] = base64[c]; |
okini3939 | 0:f2bf5f966801 | 38 | c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4); |
okini3939 | 0:f2bf5f966801 | 39 | output[j+1] = base64[c]; |
okini3939 | 0:f2bf5f966801 | 40 | c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6); |
okini3939 | 0:f2bf5f966801 | 41 | output[j+2] = (length>i+1)?base64[c]:'='; |
okini3939 | 0:f2bf5f966801 | 42 | c = (c3 & 0x3F); |
okini3939 | 0:f2bf5f966801 | 43 | output[j+3] = (length>i+2)?base64[c]:'='; |
okini3939 | 0:f2bf5f966801 | 44 | } |
okini3939 | 0:f2bf5f966801 | 45 | output[(((length-1)/3)+1)<<2] = '\0'; |
okini3939 | 0:f2bf5f966801 | 46 | } |
okini3939 | 0:f2bf5f966801 | 47 | /* |
okini3939 | 0:f2bf5f966801 | 48 | // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) |
okini3939 | 0:f2bf5f966801 | 49 | int url_encode(char *str, char *buf, int len) { |
okini3939 | 0:f2bf5f966801 | 50 | // char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf; |
okini3939 | 0:f2bf5f966801 | 51 | if (len < strlen(str) * 3 + 1) return -1; |
okini3939 | 0:f2bf5f966801 | 52 | char *pstr = str, *pbuf = buf; |
okini3939 | 0:f2bf5f966801 | 53 | while (*pstr) { |
okini3939 | 0:f2bf5f966801 | 54 | if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') |
okini3939 | 0:f2bf5f966801 | 55 | *pbuf++ = *pstr; |
okini3939 | 0:f2bf5f966801 | 56 | else if (*pstr == ' ') |
okini3939 | 0:f2bf5f966801 | 57 | *pbuf++ = '+'; |
okini3939 | 0:f2bf5f966801 | 58 | else |
okini3939 | 0:f2bf5f966801 | 59 | *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); |
okini3939 | 0:f2bf5f966801 | 60 | pstr++; |
okini3939 | 0:f2bf5f966801 | 61 | } |
okini3939 | 0:f2bf5f966801 | 62 | *pbuf = '\0'; |
okini3939 | 0:f2bf5f966801 | 63 | return 0; |
okini3939 | 0:f2bf5f966801 | 64 | } |
okini3939 | 0:f2bf5f966801 | 65 | */ |
okini3939 | 0:f2bf5f966801 | 66 | |
okini3939 | 0:f2bf5f966801 | 67 | void isr_http (TCPSocketEvent e) { |
okini3939 | 0:f2bf5f966801 | 68 | |
okini3939 | 0:f2bf5f966801 | 69 | #ifdef DEBUG |
okini3939 | 0:f2bf5f966801 | 70 | printf("tcp(%d)\r\n", e); |
okini3939 | 0:f2bf5f966801 | 71 | #endif |
okini3939 | 0:f2bf5f966801 | 72 | switch(e) { |
okini3939 | 0:f2bf5f966801 | 73 | case TCPSOCKET_READABLE: //Incoming data |
okini3939 | 0:f2bf5f966801 | 74 | tcp_status = STATUS_READABLE; |
okini3939 | 0:f2bf5f966801 | 75 | break; |
okini3939 | 0:f2bf5f966801 | 76 | |
okini3939 | 0:f2bf5f966801 | 77 | case TCPSOCKET_CONNECTED: |
okini3939 | 0:f2bf5f966801 | 78 | case TCPSOCKET_WRITEABLE: //We can send data |
okini3939 | 0:f2bf5f966801 | 79 | tcp_status = STATUS_CONNECTED; |
okini3939 | 0:f2bf5f966801 | 80 | break; |
okini3939 | 0:f2bf5f966801 | 81 | |
okini3939 | 0:f2bf5f966801 | 82 | case TCPSOCKET_CONTIMEOUT: |
okini3939 | 0:f2bf5f966801 | 83 | case TCPSOCKET_CONRST: |
okini3939 | 0:f2bf5f966801 | 84 | case TCPSOCKET_CONABRT: |
okini3939 | 0:f2bf5f966801 | 85 | case TCPSOCKET_ERROR: |
okini3939 | 0:f2bf5f966801 | 86 | tcp_status = STATUS_ERROR; |
okini3939 | 0:f2bf5f966801 | 87 | break; |
okini3939 | 0:f2bf5f966801 | 88 | |
okini3939 | 0:f2bf5f966801 | 89 | case TCPSOCKET_DISCONNECTED: |
okini3939 | 0:f2bf5f966801 | 90 | tcp_status = STATUS_DISCONNECTED; |
okini3939 | 0:f2bf5f966801 | 91 | break; |
okini3939 | 0:f2bf5f966801 | 92 | } |
okini3939 | 0:f2bf5f966801 | 93 | } |
okini3939 | 0:f2bf5f966801 | 94 | |
okini3939 | 0:f2bf5f966801 | 95 | void createauth (char *user, char *pwd, char *buf) { |
okini3939 | 0:f2bf5f966801 | 96 | char tmp[80]; |
okini3939 | 0:f2bf5f966801 | 97 | |
okini3939 | 0:f2bf5f966801 | 98 | snprintf(tmp, sizeof(tmp), "Authorization: Basic %s:%s\n", user, pwd); |
okini3939 | 0:f2bf5f966801 | 99 | base64enc(tmp, strlen(tmp), buf); |
okini3939 | 0:f2bf5f966801 | 100 | } |
okini3939 | 0:f2bf5f966801 | 101 | |
okini3939 | 0:f2bf5f966801 | 102 | void isr_dns (DNSReply r) { |
okini3939 | 0:f2bf5f966801 | 103 | |
okini3939 | 0:f2bf5f966801 | 104 | if (DNS_FOUND) { |
okini3939 | 0:f2bf5f966801 | 105 | dns_status = 1; |
okini3939 | 0:f2bf5f966801 | 106 | } else { |
okini3939 | 0:f2bf5f966801 | 107 | dns_status = -1; |
okini3939 | 0:f2bf5f966801 | 108 | } |
okini3939 | 0:f2bf5f966801 | 109 | } |
okini3939 | 0:f2bf5f966801 | 110 | |
okini3939 | 0:f2bf5f966801 | 111 | int httpRequest (int method, Host *host, char *uri, char *head, char *body) { |
okini3939 | 0:f2bf5f966801 | 112 | TCPSocketErr err; |
okini3939 | 0:f2bf5f966801 | 113 | char buf[500]; |
okini3939 | 0:f2bf5f966801 | 114 | int i, ret = -1; |
okini3939 | 0:f2bf5f966801 | 115 | |
okini3939 | 0:f2bf5f966801 | 116 | http = new TCPSocket; |
okini3939 | 0:f2bf5f966801 | 117 | tcp_status = STATUS_NONE; |
okini3939 | 0:f2bf5f966801 | 118 | |
okini3939 | 0:f2bf5f966801 | 119 | http->setOnEvent(isr_http); |
okini3939 | 0:f2bf5f966801 | 120 | |
okini3939 | 0:f2bf5f966801 | 121 | // connect |
okini3939 | 0:f2bf5f966801 | 122 | if (host->getIp().isNull()) { |
okini3939 | 0:f2bf5f966801 | 123 | DNSRequest dns; |
okini3939 | 0:f2bf5f966801 | 124 | dns_status = 0; |
okini3939 | 0:f2bf5f966801 | 125 | dns.setOnReply(isr_dns); |
okini3939 | 0:f2bf5f966801 | 126 | if (dns.resolve(host) != DNS_OK) goto exit; |
okini3939 | 0:f2bf5f966801 | 127 | for (i = 0; i < HTTP_TIMEOUT / 10; i ++) { |
okini3939 | 0:f2bf5f966801 | 128 | if (dns_status) break; |
okini3939 | 0:f2bf5f966801 | 129 | Net::poll(); |
okini3939 | 0:f2bf5f966801 | 130 | wait_ms(10); |
okini3939 | 0:f2bf5f966801 | 131 | } |
okini3939 | 0:f2bf5f966801 | 132 | while (dns_status < 0) goto exit; |
okini3939 | 0:f2bf5f966801 | 133 | } |
okini3939 | 0:f2bf5f966801 | 134 | if (! host->getPort()) { |
okini3939 | 0:f2bf5f966801 | 135 | host->setPort(HTTP_PORT); |
okini3939 | 0:f2bf5f966801 | 136 | } |
okini3939 | 0:f2bf5f966801 | 137 | err = http->connect(*host); |
okini3939 | 0:f2bf5f966801 | 138 | if (err != TCPSOCKET_OK) goto exit; |
okini3939 | 0:f2bf5f966801 | 139 | |
okini3939 | 0:f2bf5f966801 | 140 | // wait connect |
okini3939 | 0:f2bf5f966801 | 141 | for (i = 0; i < HTTP_TIMEOUT / 10; i ++) { |
okini3939 | 0:f2bf5f966801 | 142 | if (tcp_status != STATUS_NONE) break; |
okini3939 | 0:f2bf5f966801 | 143 | Net::poll(); |
okini3939 | 0:f2bf5f966801 | 144 | wait_ms(10); |
okini3939 | 0:f2bf5f966801 | 145 | } |
okini3939 | 0:f2bf5f966801 | 146 | if (tcp_status != STATUS_CONNECTED) goto exit; |
okini3939 | 0:f2bf5f966801 | 147 | |
okini3939 | 0:f2bf5f966801 | 148 | // send request |
okini3939 | 0:f2bf5f966801 | 149 | if (method == METHOD_POST) { |
okini3939 | 0:f2bf5f966801 | 150 | http->send("POST ", 5); |
okini3939 | 0:f2bf5f966801 | 151 | } else { |
okini3939 | 0:f2bf5f966801 | 152 | http->send("GET ", 4); |
okini3939 | 0:f2bf5f966801 | 153 | } |
okini3939 | 0:f2bf5f966801 | 154 | http->send(uri, strlen(uri)); |
okini3939 | 0:f2bf5f966801 | 155 | http->send(" HTTP/1.1\r\nHost: ", 17); |
okini3939 | 0:f2bf5f966801 | 156 | http->send(host->getName(), strlen(host->getName())); |
okini3939 | 0:f2bf5f966801 | 157 | http->send("\r\n", 2); |
okini3939 | 1:9f15e579d914 | 158 | http->send("Connection: close\r\n", 19); |
okini3939 | 0:f2bf5f966801 | 159 | if (head) { |
okini3939 | 0:f2bf5f966801 | 160 | http->send(head, strlen(head)); |
okini3939 | 0:f2bf5f966801 | 161 | } |
okini3939 | 0:f2bf5f966801 | 162 | if (method == METHOD_POST) { |
okini3939 | 0:f2bf5f966801 | 163 | sprintf(buf, "Content-Length: %d\r\n", strlen(body)); |
okini3939 | 0:f2bf5f966801 | 164 | http->send(buf, strlen(buf)); |
okini3939 | 0:f2bf5f966801 | 165 | } |
okini3939 | 0:f2bf5f966801 | 166 | http->send("\r\n", 2); |
okini3939 | 0:f2bf5f966801 | 167 | |
okini3939 | 0:f2bf5f966801 | 168 | // post method |
okini3939 | 0:f2bf5f966801 | 169 | if (method == METHOD_POST && body) { |
okini3939 | 0:f2bf5f966801 | 170 | http->send(body, strlen(body)); |
okini3939 | 0:f2bf5f966801 | 171 | } |
okini3939 | 0:f2bf5f966801 | 172 | |
okini3939 | 0:f2bf5f966801 | 173 | // wait responce |
okini3939 | 0:f2bf5f966801 | 174 | for (i = 0; i < 1500; i ++) { |
okini3939 | 0:f2bf5f966801 | 175 | if (tcp_status != STATUS_CONNECTED) break; |
okini3939 | 0:f2bf5f966801 | 176 | Net::poll(); |
okini3939 | 0:f2bf5f966801 | 177 | wait_ms(10); |
okini3939 | 0:f2bf5f966801 | 178 | } |
okini3939 | 0:f2bf5f966801 | 179 | if (tcp_status != STATUS_READABLE) goto exit; |
okini3939 | 0:f2bf5f966801 | 180 | |
okini3939 | 0:f2bf5f966801 | 181 | // recv responce |
okini3939 | 0:f2bf5f966801 | 182 | i = http->recv(buf, sizeof(buf)); |
okini3939 | 0:f2bf5f966801 | 183 | buf[i] = 0; |
okini3939 | 0:f2bf5f966801 | 184 | if (strncmp(buf, "HTTP", 4) == 0) { |
okini3939 | 0:f2bf5f966801 | 185 | ret = atoi(&buf[9]); |
okini3939 | 0:f2bf5f966801 | 186 | } |
okini3939 | 0:f2bf5f966801 | 187 | #ifdef DEBUG |
okini3939 | 0:f2bf5f966801 | 188 | printf(buf); |
okini3939 | 0:f2bf5f966801 | 189 | #endif |
okini3939 | 0:f2bf5f966801 | 190 | |
okini3939 | 0:f2bf5f966801 | 191 | // recv dummy |
okini3939 | 0:f2bf5f966801 | 192 | for (i = 0; i < HTTP_TIMEOUT / 10; i ++) { |
okini3939 | 0:f2bf5f966801 | 193 | switch (tcp_status) { |
okini3939 | 0:f2bf5f966801 | 194 | case STATUS_READABLE: |
okini3939 | 0:f2bf5f966801 | 195 | int n = http->recv(buf, sizeof(buf)); |
okini3939 | 0:f2bf5f966801 | 196 | buf[n] = 0; |
okini3939 | 0:f2bf5f966801 | 197 | i = 0; |
okini3939 | 0:f2bf5f966801 | 198 | #ifdef DEBUG |
okini3939 | 0:f2bf5f966801 | 199 | printf(buf); |
okini3939 | 0:f2bf5f966801 | 200 | #endif |
okini3939 | 0:f2bf5f966801 | 201 | break; |
okini3939 | 0:f2bf5f966801 | 202 | case STATUS_DISCONNECTED: |
okini3939 | 0:f2bf5f966801 | 203 | case STATUS_ERROR: |
okini3939 | 0:f2bf5f966801 | 204 | goto exit; |
okini3939 | 0:f2bf5f966801 | 205 | } |
okini3939 | 0:f2bf5f966801 | 206 | Net::poll(); |
okini3939 | 0:f2bf5f966801 | 207 | wait_ms(10); |
okini3939 | 0:f2bf5f966801 | 208 | } |
okini3939 | 0:f2bf5f966801 | 209 | |
okini3939 | 0:f2bf5f966801 | 210 | exit: |
okini3939 | 0:f2bf5f966801 | 211 | http->resetOnEvent(); |
okini3939 | 0:f2bf5f966801 | 212 | http->close(); |
okini3939 | 0:f2bf5f966801 | 213 | delete http; |
okini3939 | 0:f2bf5f966801 | 214 | |
okini3939 | 0:f2bf5f966801 | 215 | return ret; |
okini3939 | 0:f2bf5f966801 | 216 | } |