Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
TASS Belgium NV
Date:
Mon Dec 16 11:25:54 2013 +0100
Revision:
131:4758606c9316
Parent:
125:96003ae6f1d8
Child:
134:cc4e6d2654d9
Syncronized with master branch

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tass 68:0847e35d08a6 1 /*********************************************************************
TASS Belgium NV 131:4758606c9316 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
TASS Belgium NV 131:4758606c9316 3 See LICENSE and COPYING for usage.
tass 68:0847e35d08a6 4
TASS Belgium NV 131:4758606c9316 5 Author: Andrei Carp <andrei.carp@tass.be>
TASS Belgium NV 131:4758606c9316 6 *********************************************************************/
tass 68:0847e35d08a6 7 #include <string.h>
tass 68:0847e35d08a6 8 #include <stdint.h>
tass 68:0847e35d08a6 9 #include "pico_tree.h"
tass 68:0847e35d08a6 10 #include "pico_config.h"
tass 68:0847e35d08a6 11 #include "pico_socket.h"
tass 68:0847e35d08a6 12 #include "pico_tcp.h"
tass 68:0847e35d08a6 13 #include "pico_dns_client.h"
tass 68:0847e35d08a6 14 #include "pico_http_client.h"
tass 68:0847e35d08a6 15 #include "pico_ipv4.h"
tass 68:0847e35d08a6 16 #include "pico_stack.h"
tass 68:0847e35d08a6 17
tass 68:0847e35d08a6 18 /*
tass 68:0847e35d08a6 19 * This is the size of the following header
tass 68:0847e35d08a6 20 *
tass 68:0847e35d08a6 21 * GET <resource> HTTP/1.1<CRLF>
tass 68:0847e35d08a6 22 * Host: <host>:<port><CRLF>
tass 68:0847e35d08a6 23 * User-Agent: picoTCP<CRLF>
tass 68:0847e35d08a6 24 * Connection: close<CRLF>
tass 68:0847e35d08a6 25 * <CRLF>
tass 68:0847e35d08a6 26 *
tass 68:0847e35d08a6 27 * where <resource>,<host> and <port> will be added later.
tass 68:0847e35d08a6 28 */
tass 68:0847e35d08a6 29
tass 68:0847e35d08a6 30 #ifdef PICO_SUPPORT_HTTP_CLIENT
tass 68:0847e35d08a6 31
tass 68:0847e35d08a6 32 #define HTTP_GET_BASIC_SIZE 63u
tass 68:0847e35d08a6 33 #define HTTP_HEADER_LINE_SIZE 50u
TASS Belgium NV 131:4758606c9316 34 #define RESPONSE_INDEX 9u
tass 68:0847e35d08a6 35
TASS Belgium NV 131:4758606c9316 36 #define HTTP_CHUNK_ERROR 0xFFFFFFFFu
tass 68:0847e35d08a6 37
tass 68:0847e35d08a6 38 #ifdef dbg
TASS Belgium NV 131:4758606c9316 39 #undef dbg
tass 68:0847e35d08a6 40 #endif
tass 68:0847e35d08a6 41
TASS Belgium NV 131:4758606c9316 42 #define dbg(...) do {} while(0)
TASS Belgium NV 131:4758606c9316 43 #define nop() do {} while(0)
tass 123:dd26752a4538 44
TASS Belgium NV 131:4758606c9316 45 #define consumeChar(c) (pico_socket_read(client->sck, &c, 1u))
TASS Belgium NV 131:4758606c9316 46 #define isLocation(line) (memcmp(line, "Location", 8u) == 0)
TASS Belgium NV 131:4758606c9316 47 #define isContentLength(line) (memcmp(line, "Content-Length", 14u) == 0u)
TASS Belgium NV 131:4758606c9316 48 #define isTransferEncoding(line) (memcmp(line, "Transfer-Encoding", 17u) == 0u)
TASS Belgium NV 131:4758606c9316 49 #define isChunked(line) (memcmp(line, " chunked", 8u) == 0u)
TASS Belgium NV 131:4758606c9316 50 #define isNotHTTPv1(line) (memcmp(line, "HTTP/1.", 7u))
tass 123:dd26752a4538 51 #define is_hex_digit(x) ((('0' <= x) && (x <= '9')) || (('a' <= x) && (x <= 'f')))
TASS Belgium NV 131:4758606c9316 52 #define hex_digit_to_dec(x) ((('0' <= x) && (x <= '9')) ? (x - '0') : ((('a' <= x) && (x <= 'f')) ? (x - 'a' + 10) : (-1)))
tass 68:0847e35d08a6 53
tass 68:0847e35d08a6 54 struct pico_http_client
tass 68:0847e35d08a6 55 {
TASS Belgium NV 131:4758606c9316 56 uint16_t connectionID;
TASS Belgium NV 131:4758606c9316 57 uint8_t state;
TASS Belgium NV 131:4758606c9316 58 struct pico_socket *sck;
TASS Belgium NV 131:4758606c9316 59 void (*wakeup)(uint16_t ev, uint16_t conn);
TASS Belgium NV 131:4758606c9316 60 struct pico_ip4 ip;
TASS Belgium NV 131:4758606c9316 61 struct pico_http_uri *uriKey;
TASS Belgium NV 131:4758606c9316 62 struct pico_http_header *header;
tass 68:0847e35d08a6 63 };
tass 68:0847e35d08a6 64
TASS Belgium NV 131:4758606c9316 65 /* HTTP Client internal states */
tass 68:0847e35d08a6 66 #define HTTP_READING_HEADER 0
TASS Belgium NV 131:4758606c9316 67 #define HTTP_READING_BODY 1
tass 68:0847e35d08a6 68 #define HTTP_READING_CHUNK_VALUE 2
tass 68:0847e35d08a6 69 #define HTTP_READING_CHUNK_TRAIL 3
tass 68:0847e35d08a6 70
tass 68:0847e35d08a6 71
TASS Belgium NV 131:4758606c9316 72 static int compareClients(void *ka, void *kb)
tass 68:0847e35d08a6 73 {
TASS Belgium NV 131:4758606c9316 74 return ((struct pico_http_client *)ka)->connectionID - ((struct pico_http_client *)kb)->connectionID;
tass 68:0847e35d08a6 75 }
tass 68:0847e35d08a6 76
TASS Belgium NV 131:4758606c9316 77 PICO_TREE_DECLARE(pico_client_list, compareClients);
tass 68:0847e35d08a6 78
TASS Belgium NV 131:4758606c9316 79 /* Local functions */
TASS Belgium NV 131:4758606c9316 80 int parseHeaderFromServer(struct pico_http_client *client, struct pico_http_header *header);
TASS Belgium NV 131:4758606c9316 81 int readChunkLine(struct pico_http_client *client);
TASS Belgium NV 131:4758606c9316 82 /* */
TASS Belgium NV 131:4758606c9316 83 static inline void processConnErrClose(uint16_t ev, struct pico_http_client *client)
tass 125:96003ae6f1d8 84 {
TASS Belgium NV 131:4758606c9316 85 if(ev & PICO_SOCK_EV_CONN)
TASS Belgium NV 131:4758606c9316 86 client->wakeup(EV_HTTP_CON, client->connectionID);
tass 68:0847e35d08a6 87
TASS Belgium NV 131:4758606c9316 88 if(ev & PICO_SOCK_EV_ERR)
TASS Belgium NV 131:4758606c9316 89 {
TASS Belgium NV 131:4758606c9316 90 client->wakeup(EV_HTTP_ERROR, client->connectionID);
TASS Belgium NV 131:4758606c9316 91 }
tass 125:96003ae6f1d8 92
TASS Belgium NV 131:4758606c9316 93 if((ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN))
TASS Belgium NV 131:4758606c9316 94 {
TASS Belgium NV 131:4758606c9316 95 client->wakeup(EV_HTTP_CLOSE, client->connectionID);
TASS Belgium NV 131:4758606c9316 96 }
tass 125:96003ae6f1d8 97 }
tass 125:96003ae6f1d8 98
TASS Belgium NV 131:4758606c9316 99 static inline void waitForHeader(struct pico_http_client *client)
tass 125:96003ae6f1d8 100 {
TASS Belgium NV 131:4758606c9316 101 /* wait for header */
TASS Belgium NV 131:4758606c9316 102 if(parseHeaderFromServer(client, client->header) < 0)
TASS Belgium NV 131:4758606c9316 103 {
TASS Belgium NV 131:4758606c9316 104 client->wakeup(EV_HTTP_ERROR, client->connectionID);
TASS Belgium NV 131:4758606c9316 105 }
TASS Belgium NV 131:4758606c9316 106 else
TASS Belgium NV 131:4758606c9316 107 {
TASS Belgium NV 131:4758606c9316 108 /* call wakeup */
TASS Belgium NV 131:4758606c9316 109 if(client->header->responseCode != HTTP_CONTINUE)
TASS Belgium NV 131:4758606c9316 110 {
TASS Belgium NV 131:4758606c9316 111 client->wakeup(
TASS Belgium NV 131:4758606c9316 112 (client->header->responseCode == HTTP_OK) ?
TASS Belgium NV 131:4758606c9316 113 (EV_HTTP_REQ | EV_HTTP_BODY) : /* data comes for sure only when 200 is received */
TASS Belgium NV 131:4758606c9316 114 EV_HTTP_REQ
TASS Belgium NV 131:4758606c9316 115 , client->connectionID);
TASS Belgium NV 131:4758606c9316 116 }
TASS Belgium NV 131:4758606c9316 117 }
tass 125:96003ae6f1d8 118 }
tass 125:96003ae6f1d8 119
TASS Belgium NV 131:4758606c9316 120 static inline void treatReadEvent(struct pico_http_client *client)
tass 125:96003ae6f1d8 121 {
TASS Belgium NV 131:4758606c9316 122 /* read the header, if not read */
TASS Belgium NV 131:4758606c9316 123 if(client->state == HTTP_READING_HEADER)
TASS Belgium NV 131:4758606c9316 124 {
TASS Belgium NV 131:4758606c9316 125 /* wait for header */
TASS Belgium NV 131:4758606c9316 126 client->header = pico_zalloc(sizeof(struct pico_http_header));
TASS Belgium NV 131:4758606c9316 127 if(!client->header)
TASS Belgium NV 131:4758606c9316 128 {
TASS Belgium NV 131:4758606c9316 129 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 130 return;
TASS Belgium NV 131:4758606c9316 131 }
tass 125:96003ae6f1d8 132
TASS Belgium NV 131:4758606c9316 133 waitForHeader(client);
TASS Belgium NV 131:4758606c9316 134 }
TASS Belgium NV 131:4758606c9316 135 else
TASS Belgium NV 131:4758606c9316 136 {
TASS Belgium NV 131:4758606c9316 137 /* just let the user know that data has arrived, if chunked data comes, will be treated in the */
TASS Belgium NV 131:4758606c9316 138 /* read api. */
TASS Belgium NV 131:4758606c9316 139 client->wakeup(EV_HTTP_BODY, client->connectionID);
TASS Belgium NV 131:4758606c9316 140 }
tass 125:96003ae6f1d8 141 }
tass 68:0847e35d08a6 142 void tcpCallback(uint16_t ev, struct pico_socket *s)
tass 68:0847e35d08a6 143 {
tass 68:0847e35d08a6 144
TASS Belgium NV 131:4758606c9316 145 struct pico_http_client *client = NULL;
TASS Belgium NV 131:4758606c9316 146 struct pico_tree_node *index;
tass 68:0847e35d08a6 147
TASS Belgium NV 131:4758606c9316 148 /* find httpClient */
TASS Belgium NV 131:4758606c9316 149 pico_tree_foreach(index, &pico_client_list)
TASS Belgium NV 131:4758606c9316 150 {
TASS Belgium NV 131:4758606c9316 151 if(((struct pico_http_client *)index->keyValue)->sck == s )
TASS Belgium NV 131:4758606c9316 152 {
TASS Belgium NV 131:4758606c9316 153 client = (struct pico_http_client *)index->keyValue;
TASS Belgium NV 131:4758606c9316 154 break;
TASS Belgium NV 131:4758606c9316 155 }
TASS Belgium NV 131:4758606c9316 156 }
tass 68:0847e35d08a6 157
TASS Belgium NV 131:4758606c9316 158 if(!client)
TASS Belgium NV 131:4758606c9316 159 {
TASS Belgium NV 131:4758606c9316 160 dbg("Client not found...Something went wrong !\n");
TASS Belgium NV 131:4758606c9316 161 return;
TASS Belgium NV 131:4758606c9316 162 }
tass 68:0847e35d08a6 163
TASS Belgium NV 131:4758606c9316 164 processConnErrClose(ev, client);
tass 68:0847e35d08a6 165
TASS Belgium NV 131:4758606c9316 166 if(ev & PICO_SOCK_EV_RD)
TASS Belgium NV 131:4758606c9316 167 {
TASS Belgium NV 131:4758606c9316 168 treatReadEvent(client);
tass 68:0847e35d08a6 169
TASS Belgium NV 131:4758606c9316 170 }
tass 68:0847e35d08a6 171 }
tass 68:0847e35d08a6 172
TASS Belgium NV 131:4758606c9316 173 /* used for getting a response from DNS servers */
TASS Belgium NV 131:4758606c9316 174 static void dnsCallback(char *ip, void *ptr)
tass 68:0847e35d08a6 175 {
TASS Belgium NV 131:4758606c9316 176 struct pico_http_client *client = (struct pico_http_client *)ptr;
tass 68:0847e35d08a6 177
TASS Belgium NV 131:4758606c9316 178 if(!client)
TASS Belgium NV 131:4758606c9316 179 {
TASS Belgium NV 131:4758606c9316 180 dbg("Who made the request ?!\n");
TASS Belgium NV 131:4758606c9316 181 return;
TASS Belgium NV 131:4758606c9316 182 }
tass 68:0847e35d08a6 183
TASS Belgium NV 131:4758606c9316 184 if(ip)
TASS Belgium NV 131:4758606c9316 185 {
TASS Belgium NV 131:4758606c9316 186 client->wakeup(EV_HTTP_DNS, client->connectionID);
tass 68:0847e35d08a6 187
TASS Belgium NV 131:4758606c9316 188 /* add the ip address to the client, and start a tcp connection socket */
TASS Belgium NV 131:4758606c9316 189 pico_string_to_ipv4(ip, &client->ip.addr);
TASS Belgium NV 131:4758606c9316 190 pico_free(ip);
TASS Belgium NV 131:4758606c9316 191 client->sck = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &tcpCallback);
TASS Belgium NV 131:4758606c9316 192 if(!client->sck)
TASS Belgium NV 131:4758606c9316 193 {
TASS Belgium NV 131:4758606c9316 194 client->wakeup(EV_HTTP_ERROR, client->connectionID);
TASS Belgium NV 131:4758606c9316 195 return;
TASS Belgium NV 131:4758606c9316 196 }
tass 68:0847e35d08a6 197
TASS Belgium NV 131:4758606c9316 198 if(pico_socket_connect(client->sck, &client->ip, short_be(client->uriKey->port)) < 0)
TASS Belgium NV 131:4758606c9316 199 {
TASS Belgium NV 131:4758606c9316 200 client->wakeup(EV_HTTP_ERROR, client->connectionID);
TASS Belgium NV 131:4758606c9316 201 return;
TASS Belgium NV 131:4758606c9316 202 }
tass 68:0847e35d08a6 203
TASS Belgium NV 131:4758606c9316 204 }
TASS Belgium NV 131:4758606c9316 205 else
TASS Belgium NV 131:4758606c9316 206 {
TASS Belgium NV 131:4758606c9316 207 /* wakeup client and let know error occured */
TASS Belgium NV 131:4758606c9316 208 client->wakeup(EV_HTTP_ERROR, client->connectionID);
tass 68:0847e35d08a6 209
TASS Belgium NV 131:4758606c9316 210 /* close the client (free used heap) */
TASS Belgium NV 131:4758606c9316 211 pico_http_client_close(client->connectionID);
TASS Belgium NV 131:4758606c9316 212 }
tass 68:0847e35d08a6 213 }
tass 68:0847e35d08a6 214
tass 68:0847e35d08a6 215 /*
tass 68:0847e35d08a6 216 * API used for opening a new HTTP Client.
tass 68:0847e35d08a6 217 *
tass 125:96003ae6f1d8 218 * The accepted uri's are [http:]hostname[:port]/resource
tass 68:0847e35d08a6 219 * no relative uri's are accepted.
tass 68:0847e35d08a6 220 *
tass 68:0847e35d08a6 221 * The function returns a connection ID >= 0 if successful
tass 68:0847e35d08a6 222 * -1 if an error occured.
tass 68:0847e35d08a6 223 */
TASS Belgium NV 131:4758606c9316 224 int pico_http_client_open(char *uri, void (*wakeup)(uint16_t ev, uint16_t conn))
tass 68:0847e35d08a6 225 {
TASS Belgium NV 131:4758606c9316 226 struct pico_http_client *client;
tass 68:0847e35d08a6 227
TASS Belgium NV 131:4758606c9316 228 client = pico_zalloc(sizeof(struct pico_http_client));
TASS Belgium NV 131:4758606c9316 229 if(!client)
TASS Belgium NV 131:4758606c9316 230 {
TASS Belgium NV 131:4758606c9316 231 /* memory error */
TASS Belgium NV 131:4758606c9316 232 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 233 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 234 }
tass 68:0847e35d08a6 235
TASS Belgium NV 131:4758606c9316 236 client->wakeup = wakeup;
TASS Belgium NV 131:4758606c9316 237 client->connectionID = (uint16_t)pico_rand() & 0x7FFFu; /* negative values mean error, still not good generation */
tass 68:0847e35d08a6 238
TASS Belgium NV 131:4758606c9316 239 client->uriKey = pico_zalloc(sizeof(struct pico_http_uri));
tass 68:0847e35d08a6 240
TASS Belgium NV 131:4758606c9316 241 if(!client->uriKey)
TASS Belgium NV 131:4758606c9316 242 {
TASS Belgium NV 131:4758606c9316 243 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 244 pico_free(client);
TASS Belgium NV 131:4758606c9316 245 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 246 }
tass 68:0847e35d08a6 247
TASS Belgium NV 131:4758606c9316 248 pico_processURI(uri, client->uriKey);
tass 68:0847e35d08a6 249
TASS Belgium NV 131:4758606c9316 250 if(pico_tree_insert(&pico_client_list, client))
TASS Belgium NV 131:4758606c9316 251 {
TASS Belgium NV 131:4758606c9316 252 /* already in */
TASS Belgium NV 131:4758606c9316 253 pico_err = PICO_ERR_EEXIST;
TASS Belgium NV 131:4758606c9316 254 pico_free(client->uriKey);
TASS Belgium NV 131:4758606c9316 255 pico_free(client);
TASS Belgium NV 131:4758606c9316 256 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 257 }
tass 68:0847e35d08a6 258
TASS Belgium NV 131:4758606c9316 259 /* dns query */
TASS Belgium NV 131:4758606c9316 260 dbg("Querying : %s \n", client->uriKey->host);
TASS Belgium NV 131:4758606c9316 261 pico_dns_client_getaddr(client->uriKey->host, dnsCallback, client);
tass 68:0847e35d08a6 262
TASS Belgium NV 131:4758606c9316 263 /* return the connection ID */
TASS Belgium NV 131:4758606c9316 264 return client->connectionID;
tass 68:0847e35d08a6 265 }
tass 68:0847e35d08a6 266
tass 68:0847e35d08a6 267 /*
tass 68:0847e35d08a6 268 * API for sending a header to the client.
tass 68:0847e35d08a6 269 *
tass 68:0847e35d08a6 270 * if hdr == HTTP_HEADER_RAW , then the parameter header
tass 68:0847e35d08a6 271 * is sent as it is to client.
tass 68:0847e35d08a6 272 *
tass 68:0847e35d08a6 273 * if hdr == HTTP_HEADER_DEFAULT, then the parameter header
tass 68:0847e35d08a6 274 * is ignored and the library will build the response header
tass 68:0847e35d08a6 275 * based on the uri passed when opening the client.
tass 68:0847e35d08a6 276 *
tass 68:0847e35d08a6 277 */
TASS Belgium NV 131:4758606c9316 278 int32_t pico_http_client_sendHeader(uint16_t conn, char *header, uint8_t hdr)
tass 68:0847e35d08a6 279 {
TASS Belgium NV 131:4758606c9316 280 struct pico_http_client search = {
TASS Belgium NV 131:4758606c9316 281 .connectionID = conn
TASS Belgium NV 131:4758606c9316 282 };
TASS Belgium NV 131:4758606c9316 283 struct pico_http_client *http = pico_tree_findKey(&pico_client_list, &search);
TASS Belgium NV 131:4758606c9316 284 int32_t length;
TASS Belgium NV 131:4758606c9316 285 if(!http)
TASS Belgium NV 131:4758606c9316 286 {
TASS Belgium NV 131:4758606c9316 287 dbg("Client not found !\n");
TASS Belgium NV 131:4758606c9316 288 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 289 }
tass 68:0847e35d08a6 290
TASS Belgium NV 131:4758606c9316 291 /* the api gives the possibility to the user to build the GET header */
TASS Belgium NV 131:4758606c9316 292 /* based on the uri passed when opening the client, less headache for the user */
TASS Belgium NV 131:4758606c9316 293 if(hdr == HTTP_HEADER_DEFAULT)
TASS Belgium NV 131:4758606c9316 294 {
TASS Belgium NV 131:4758606c9316 295 header = pico_http_client_buildHeader(http->uriKey);
tass 68:0847e35d08a6 296
TASS Belgium NV 131:4758606c9316 297 if(!header)
TASS Belgium NV 131:4758606c9316 298 {
TASS Belgium NV 131:4758606c9316 299 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 300 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 301 }
TASS Belgium NV 131:4758606c9316 302 }
tass 68:0847e35d08a6 303
TASS Belgium NV 131:4758606c9316 304 length = pico_socket_write(http->sck, (void *)header, (int)strlen(header) + 1);
tass 68:0847e35d08a6 305
TASS Belgium NV 131:4758606c9316 306 if(hdr == HTTP_HEADER_DEFAULT)
TASS Belgium NV 131:4758606c9316 307 pico_free(header);
tass 68:0847e35d08a6 308
TASS Belgium NV 131:4758606c9316 309 return length;
tass 68:0847e35d08a6 310 }
tass 68:0847e35d08a6 311
tass 125:96003ae6f1d8 312
TASS Belgium NV 131:4758606c9316 313 /* / */
tass 125:96003ae6f1d8 314
TASS Belgium NV 131:4758606c9316 315 static inline int checkChunkLine(struct pico_http_client *client, int tmpLenRead)
tass 125:96003ae6f1d8 316 {
TASS Belgium NV 131:4758606c9316 317 if(readChunkLine(client) == HTTP_RETURN_ERROR)
TASS Belgium NV 131:4758606c9316 318 {
TASS Belgium NV 131:4758606c9316 319 dbg("Probably the chunk is malformed or parsed wrong...\n");
TASS Belgium NV 131:4758606c9316 320 client->wakeup(EV_HTTP_ERROR, client->connectionID);
TASS Belgium NV 131:4758606c9316 321 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 322 }
tass 125:96003ae6f1d8 323
TASS Belgium NV 131:4758606c9316 324 if(client->state != HTTP_READING_BODY || !tmpLenRead)
TASS Belgium NV 131:4758606c9316 325 return 0; /* force out */
tass 125:96003ae6f1d8 326
TASS Belgium NV 131:4758606c9316 327 return 1;
tass 125:96003ae6f1d8 328 }
tass 125:96003ae6f1d8 329
TASS Belgium NV 131:4758606c9316 330 static inline void updateContentLength(struct pico_http_client *client, int tmpLenRead )
tass 125:96003ae6f1d8 331 {
TASS Belgium NV 131:4758606c9316 332 if(tmpLenRead > 0)
TASS Belgium NV 131:4758606c9316 333 {
TASS Belgium NV 131:4758606c9316 334 client->header->contentLengthOrChunk = client->header->contentLengthOrChunk - (uint32_t)tmpLenRead;
TASS Belgium NV 131:4758606c9316 335 }
tass 125:96003ae6f1d8 336 }
tass 125:96003ae6f1d8 337
TASS Belgium NV 131:4758606c9316 338 static inline int readBody(struct pico_http_client *client, char *data, uint16_t size, int *lenRead, int *tmpLenRead)
tass 125:96003ae6f1d8 339 {
TASS Belgium NV 131:4758606c9316 340 *tmpLenRead = 0;
tass 125:96003ae6f1d8 341
TASS Belgium NV 131:4758606c9316 342 if(client->state == HTTP_READING_BODY)
TASS Belgium NV 131:4758606c9316 343 {
tass 125:96003ae6f1d8 344
TASS Belgium NV 131:4758606c9316 345 /* if needed truncate the data */
TASS Belgium NV 131:4758606c9316 346 *tmpLenRead = pico_socket_read(client->sck, data + (*lenRead),
TASS Belgium NV 131:4758606c9316 347 (client->header->contentLengthOrChunk < ((uint32_t)(size - (*lenRead)))) ? ((int)client->header->contentLengthOrChunk) : (size - (*lenRead)));
tass 125:96003ae6f1d8 348
TASS Belgium NV 131:4758606c9316 349 updateContentLength(client, *tmpLenRead);
TASS Belgium NV 131:4758606c9316 350 if(*tmpLenRead < 0)
TASS Belgium NV 131:4758606c9316 351 {
TASS Belgium NV 131:4758606c9316 352 /* error on reading */
TASS Belgium NV 131:4758606c9316 353 dbg(">>> Error returned pico_socket_read\n");
TASS Belgium NV 131:4758606c9316 354 pico_err = PICO_ERR_EBUSY;
TASS Belgium NV 131:4758606c9316 355 /* return how much data was read until now */
TASS Belgium NV 131:4758606c9316 356 return (*lenRead);
TASS Belgium NV 131:4758606c9316 357 }
TASS Belgium NV 131:4758606c9316 358 }
tass 125:96003ae6f1d8 359
TASS Belgium NV 131:4758606c9316 360 *lenRead += *tmpLenRead;
TASS Belgium NV 131:4758606c9316 361 return 0;
tass 125:96003ae6f1d8 362 }
tass 125:96003ae6f1d8 363
TASS Belgium NV 131:4758606c9316 364 static inline int readBigChunk(struct pico_http_client *client, char *data, uint16_t size, int *lenRead)
tass 125:96003ae6f1d8 365 {
TASS Belgium NV 131:4758606c9316 366 int value;
TASS Belgium NV 131:4758606c9316 367 /* check if we need more than one chunk */
TASS Belgium NV 131:4758606c9316 368 if(size >= client->header->contentLengthOrChunk)
TASS Belgium NV 131:4758606c9316 369 {
TASS Belgium NV 131:4758606c9316 370 /* read the rest of the chunk, if chunk is done, proceed to the next chunk */
TASS Belgium NV 131:4758606c9316 371 while((uint16_t)(*lenRead) <= size)
TASS Belgium NV 131:4758606c9316 372 {
TASS Belgium NV 131:4758606c9316 373 int tmpLenRead = 0;
TASS Belgium NV 131:4758606c9316 374 if(readBody(client, data, size, lenRead, &tmpLenRead))
TASS Belgium NV 131:4758606c9316 375 return (*lenRead);
tass 125:96003ae6f1d8 376
TASS Belgium NV 131:4758606c9316 377 if((value = checkChunkLine(client, tmpLenRead)) <= 0)
TASS Belgium NV 131:4758606c9316 378 return value;
TASS Belgium NV 131:4758606c9316 379 }
TASS Belgium NV 131:4758606c9316 380 }
TASS Belgium NV 131:4758606c9316 381
TASS Belgium NV 131:4758606c9316 382 return 0;
tass 125:96003ae6f1d8 383 }
tass 125:96003ae6f1d8 384
TASS Belgium NV 131:4758606c9316 385 static inline void readSmallChunk(struct pico_http_client *client, char *data, uint16_t size, int *lenRead)
tass 125:96003ae6f1d8 386 {
TASS Belgium NV 131:4758606c9316 387 if(size < client->header->contentLengthOrChunk)
TASS Belgium NV 131:4758606c9316 388 {
TASS Belgium NV 131:4758606c9316 389 /* read the data from the chunk */
TASS Belgium NV 131:4758606c9316 390 *lenRead = pico_socket_read(client->sck, (void *)data, size);
tass 125:96003ae6f1d8 391
TASS Belgium NV 131:4758606c9316 392 if(*lenRead)
TASS Belgium NV 131:4758606c9316 393 client->header->contentLengthOrChunk = client->header->contentLengthOrChunk - (uint32_t)(*lenRead);
TASS Belgium NV 131:4758606c9316 394 }
tass 125:96003ae6f1d8 395 }
TASS Belgium NV 131:4758606c9316 396 static inline int readChunkedData(struct pico_http_client *client, char *data, uint16_t size)
tass 125:96003ae6f1d8 397 {
TASS Belgium NV 131:4758606c9316 398 int lenRead = 0;
TASS Belgium NV 131:4758606c9316 399 int value;
TASS Belgium NV 131:4758606c9316 400 /* read the chunk line */
TASS Belgium NV 131:4758606c9316 401 if(readChunkLine(client) == HTTP_RETURN_ERROR)
TASS Belgium NV 131:4758606c9316 402 {
TASS Belgium NV 131:4758606c9316 403 dbg("Probably the chunk is malformed or parsed wrong...\n");
TASS Belgium NV 131:4758606c9316 404 client->wakeup(EV_HTTP_ERROR, client->connectionID);
TASS Belgium NV 131:4758606c9316 405 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 406 }
tass 125:96003ae6f1d8 407
TASS Belgium NV 131:4758606c9316 408 /* nothing to read, no use to try */
TASS Belgium NV 131:4758606c9316 409 if(client->state != HTTP_READING_BODY)
TASS Belgium NV 131:4758606c9316 410 {
TASS Belgium NV 131:4758606c9316 411 pico_err = PICO_ERR_EAGAIN;
TASS Belgium NV 131:4758606c9316 412 return HTTP_RETURN_OK;
TASS Belgium NV 131:4758606c9316 413 }
tass 125:96003ae6f1d8 414
tass 125:96003ae6f1d8 415
TASS Belgium NV 131:4758606c9316 416 readSmallChunk(client, data, size, &lenRead);
tass 125:96003ae6f1d8 417
TASS Belgium NV 131:4758606c9316 418 if((value = readBigChunk(client, data, size, &lenRead)))
TASS Belgium NV 131:4758606c9316 419 return value;
tass 125:96003ae6f1d8 420
TASS Belgium NV 131:4758606c9316 421 return lenRead;
tass 125:96003ae6f1d8 422 }
tass 125:96003ae6f1d8 423
tass 68:0847e35d08a6 424 /*
tass 68:0847e35d08a6 425 * API for reading received data.
tass 68:0847e35d08a6 426 *
tass 68:0847e35d08a6 427 * This api hides from the user if the transfer-encoding
tass 68:0847e35d08a6 428 * was chunked or a full length was provided, in case of
tass 68:0847e35d08a6 429 * a chunked transfer encoding will "de-chunk" the data
tass 68:0847e35d08a6 430 * and pass it to the user.
tass 68:0847e35d08a6 431 */
TASS Belgium NV 131:4758606c9316 432 int32_t pico_http_client_readData(uint16_t conn, char *data, uint16_t size)
tass 68:0847e35d08a6 433 {
TASS Belgium NV 131:4758606c9316 434 struct pico_http_client dummy = {
TASS Belgium NV 131:4758606c9316 435 .connectionID = conn
TASS Belgium NV 131:4758606c9316 436 };
TASS Belgium NV 131:4758606c9316 437 struct pico_http_client *client = pico_tree_findKey(&pico_client_list, &dummy);
tass 68:0847e35d08a6 438
TASS Belgium NV 131:4758606c9316 439 if(!client)
TASS Belgium NV 131:4758606c9316 440 {
TASS Belgium NV 131:4758606c9316 441 dbg("Wrong connection id !\n");
TASS Belgium NV 131:4758606c9316 442 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 443 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 444 }
tass 68:0847e35d08a6 445
TASS Belgium NV 131:4758606c9316 446 /* for the moment just read the data, do not care if it's chunked or not */
TASS Belgium NV 131:4758606c9316 447 if(client->header->transferCoding == HTTP_TRANSFER_FULL)
TASS Belgium NV 131:4758606c9316 448 return pico_socket_read(client->sck, (void *)data, size);
TASS Belgium NV 131:4758606c9316 449 else
TASS Belgium NV 131:4758606c9316 450 return readChunkedData(client, data, size);
tass 68:0847e35d08a6 451 }
tass 68:0847e35d08a6 452
tass 68:0847e35d08a6 453 /*
tass 68:0847e35d08a6 454 * API for reading received data.
tass 68:0847e35d08a6 455 *
tass 68:0847e35d08a6 456 * Reads out the header struct received from server.
tass 68:0847e35d08a6 457 */
TASS Belgium NV 131:4758606c9316 458 struct pico_http_header *pico_http_client_readHeader(uint16_t conn)
tass 68:0847e35d08a6 459 {
TASS Belgium NV 131:4758606c9316 460 struct pico_http_client dummy = {
TASS Belgium NV 131:4758606c9316 461 .connectionID = conn
TASS Belgium NV 131:4758606c9316 462 };
TASS Belgium NV 131:4758606c9316 463 struct pico_http_client *client = pico_tree_findKey(&pico_client_list, &dummy);
tass 68:0847e35d08a6 464
TASS Belgium NV 131:4758606c9316 465 if(client)
TASS Belgium NV 131:4758606c9316 466 {
TASS Belgium NV 131:4758606c9316 467 return client->header;
TASS Belgium NV 131:4758606c9316 468 }
TASS Belgium NV 131:4758606c9316 469 else
TASS Belgium NV 131:4758606c9316 470 {
TASS Belgium NV 131:4758606c9316 471 /* not found */
TASS Belgium NV 131:4758606c9316 472 dbg("Wrong connection id !\n");
TASS Belgium NV 131:4758606c9316 473 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 474 return NULL;
TASS Belgium NV 131:4758606c9316 475 }
tass 68:0847e35d08a6 476 }
tass 68:0847e35d08a6 477
tass 68:0847e35d08a6 478 /*
tass 68:0847e35d08a6 479 * API for reading received data.
tass 68:0847e35d08a6 480 *
tass 68:0847e35d08a6 481 * Reads out the uri struct after was processed.
tass 68:0847e35d08a6 482 */
TASS Belgium NV 131:4758606c9316 483 struct pico_http_uri *pico_http_client_readUriData(uint16_t conn)
tass 68:0847e35d08a6 484 {
TASS Belgium NV 131:4758606c9316 485 struct pico_http_client dummy = {
TASS Belgium NV 131:4758606c9316 486 .connectionID = conn
TASS Belgium NV 131:4758606c9316 487 };
TASS Belgium NV 131:4758606c9316 488 struct pico_http_client *client = pico_tree_findKey(&pico_client_list, &dummy);
TASS Belgium NV 131:4758606c9316 489 /* */
TASS Belgium NV 131:4758606c9316 490 if(client)
TASS Belgium NV 131:4758606c9316 491 return client->uriKey;
TASS Belgium NV 131:4758606c9316 492 else
TASS Belgium NV 131:4758606c9316 493 {
TASS Belgium NV 131:4758606c9316 494 /* not found */
TASS Belgium NV 131:4758606c9316 495 dbg("Wrong connection id !\n");
TASS Belgium NV 131:4758606c9316 496 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 497 return NULL;
TASS Belgium NV 131:4758606c9316 498 }
tass 68:0847e35d08a6 499 }
tass 68:0847e35d08a6 500
tass 68:0847e35d08a6 501 /*
tass 68:0847e35d08a6 502 * API for reading received data.
tass 68:0847e35d08a6 503 *
tass 68:0847e35d08a6 504 * Close the client.
tass 68:0847e35d08a6 505 */
TASS Belgium NV 131:4758606c9316 506 static inline void freeHeader(struct pico_http_client *toBeRemoved)
tass 125:96003ae6f1d8 507 {
TASS Belgium NV 131:4758606c9316 508 if(toBeRemoved->header)
TASS Belgium NV 131:4758606c9316 509 {
TASS Belgium NV 131:4758606c9316 510 /* free space used */
TASS Belgium NV 131:4758606c9316 511 if(toBeRemoved->header->location)
TASS Belgium NV 131:4758606c9316 512 pico_free(toBeRemoved->header->location);
tass 125:96003ae6f1d8 513
TASS Belgium NV 131:4758606c9316 514 pico_free(toBeRemoved->header);
TASS Belgium NV 131:4758606c9316 515 }
tass 125:96003ae6f1d8 516 }
tass 125:96003ae6f1d8 517
TASS Belgium NV 131:4758606c9316 518 static inline void freeUri(struct pico_http_client *toBeRemoved)
tass 125:96003ae6f1d8 519 {
TASS Belgium NV 131:4758606c9316 520 if(toBeRemoved->uriKey)
TASS Belgium NV 131:4758606c9316 521 {
TASS Belgium NV 131:4758606c9316 522 if(toBeRemoved->uriKey->host)
TASS Belgium NV 131:4758606c9316 523 pico_free(toBeRemoved->uriKey->host);
tass 125:96003ae6f1d8 524
TASS Belgium NV 131:4758606c9316 525 if(toBeRemoved->uriKey->resource)
TASS Belgium NV 131:4758606c9316 526 pico_free(toBeRemoved->uriKey->resource);
TASS Belgium NV 131:4758606c9316 527
TASS Belgium NV 131:4758606c9316 528 pico_free(toBeRemoved->uriKey);
TASS Belgium NV 131:4758606c9316 529 }
tass 125:96003ae6f1d8 530 }
tass 68:0847e35d08a6 531 int pico_http_client_close(uint16_t conn)
tass 68:0847e35d08a6 532 {
TASS Belgium NV 131:4758606c9316 533 struct pico_http_client *toBeRemoved = NULL;
TASS Belgium NV 131:4758606c9316 534 struct pico_http_client dummy = {
TASS Belgium NV 131:4758606c9316 535 0
TASS Belgium NV 131:4758606c9316 536 };
TASS Belgium NV 131:4758606c9316 537 dummy.connectionID = conn;
tass 68:0847e35d08a6 538
TASS Belgium NV 131:4758606c9316 539 dbg("Closing the client...\n");
TASS Belgium NV 131:4758606c9316 540 toBeRemoved = pico_tree_delete(&pico_client_list, &dummy);
TASS Belgium NV 131:4758606c9316 541 if(!toBeRemoved)
TASS Belgium NV 131:4758606c9316 542 {
TASS Belgium NV 131:4758606c9316 543 dbg("Warning ! Element not found ...");
TASS Belgium NV 131:4758606c9316 544 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 545 }
tass 68:0847e35d08a6 546
TASS Belgium NV 131:4758606c9316 547 /* close socket */
TASS Belgium NV 131:4758606c9316 548 if(toBeRemoved->sck)
TASS Belgium NV 131:4758606c9316 549 pico_socket_close(toBeRemoved->sck);
tass 68:0847e35d08a6 550
TASS Belgium NV 131:4758606c9316 551 freeHeader(toBeRemoved);
TASS Belgium NV 131:4758606c9316 552 freeUri(toBeRemoved);
tass 68:0847e35d08a6 553
TASS Belgium NV 131:4758606c9316 554 pico_free(toBeRemoved);
tass 68:0847e35d08a6 555
TASS Belgium NV 131:4758606c9316 556 return 0;
tass 68:0847e35d08a6 557 }
tass 68:0847e35d08a6 558
tass 68:0847e35d08a6 559 /*
tass 68:0847e35d08a6 560 * API for reading received data.
tass 68:0847e35d08a6 561 *
tass 68:0847e35d08a6 562 * Builds a GET header based on the fields on the uri.
tass 68:0847e35d08a6 563 */
TASS Belgium NV 131:4758606c9316 564 char *pico_http_client_buildHeader(const struct pico_http_uri *uriData)
tass 68:0847e35d08a6 565 {
TASS Belgium NV 131:4758606c9316 566 char *header;
TASS Belgium NV 131:4758606c9316 567 char port[6u]; /* 6 = max length of a uint16 + \0 */
tass 68:0847e35d08a6 568
TASS Belgium NV 131:4758606c9316 569 unsigned long headerSize = HTTP_GET_BASIC_SIZE;
tass 68:0847e35d08a6 570
TASS Belgium NV 131:4758606c9316 571 if(!uriData->host || !uriData->resource || !uriData->port)
TASS Belgium NV 131:4758606c9316 572 {
TASS Belgium NV 131:4758606c9316 573 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 574 return NULL;
TASS Belgium NV 131:4758606c9316 575 }
tass 68:0847e35d08a6 576
TASS Belgium NV 131:4758606c9316 577 /* */
TASS Belgium NV 131:4758606c9316 578 headerSize = (headerSize + strlen(uriData->host));
TASS Belgium NV 131:4758606c9316 579 headerSize = (headerSize + strlen(uriData->resource));
TASS Belgium NV 131:4758606c9316 580 headerSize = (headerSize + pico_itoa(uriData->port, port) + 4u); /* 3 = size(CRLF + \0) */
TASS Belgium NV 131:4758606c9316 581 header = pico_zalloc(headerSize);
tass 68:0847e35d08a6 582
TASS Belgium NV 131:4758606c9316 583 if(!header)
TASS Belgium NV 131:4758606c9316 584 {
TASS Belgium NV 131:4758606c9316 585 /* not enought memory */
TASS Belgium NV 131:4758606c9316 586 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 587 return NULL;
TASS Belgium NV 131:4758606c9316 588 }
tass 68:0847e35d08a6 589
TASS Belgium NV 131:4758606c9316 590 /* build the actual header */
TASS Belgium NV 131:4758606c9316 591 strcpy(header, "GET ");
TASS Belgium NV 131:4758606c9316 592 strcat(header, uriData->resource);
TASS Belgium NV 131:4758606c9316 593 strcat(header, " HTTP/1.1\r\n");
TASS Belgium NV 131:4758606c9316 594 strcat(header, "Host: ");
TASS Belgium NV 131:4758606c9316 595 strcat(header, uriData->host);
TASS Belgium NV 131:4758606c9316 596 strcat(header, ":");
TASS Belgium NV 131:4758606c9316 597 strcat(header, port);
TASS Belgium NV 131:4758606c9316 598 strcat(header, "\r\n");
TASS Belgium NV 131:4758606c9316 599 strcat(header, "User-Agent: picoTCP\r\nConnection: close\r\n\r\n"); /* ? */
tass 68:0847e35d08a6 600
TASS Belgium NV 131:4758606c9316 601 return header;
tass 68:0847e35d08a6 602 }
tass 68:0847e35d08a6 603
tass 125:96003ae6f1d8 604
TASS Belgium NV 131:4758606c9316 605 /* */
TASS Belgium NV 131:4758606c9316 606 static inline void readFirstLine(struct pico_http_client *client, char *line, uint32_t *index)
tass 68:0847e35d08a6 607 {
TASS Belgium NV 131:4758606c9316 608 char c;
tass 68:0847e35d08a6 609
TASS Belgium NV 131:4758606c9316 610 /* read the first line of the header */
TASS Belgium NV 131:4758606c9316 611 while(consumeChar(c) > 0 && c != '\r')
TASS Belgium NV 131:4758606c9316 612 {
TASS Belgium NV 131:4758606c9316 613 if(*index < HTTP_HEADER_LINE_SIZE) /* truncate if too long */
TASS Belgium NV 131:4758606c9316 614 line[(*index)++] = c;
TASS Belgium NV 131:4758606c9316 615 }
TASS Belgium NV 131:4758606c9316 616 consumeChar(c); /* consume \n */
tass 125:96003ae6f1d8 617 }
tass 68:0847e35d08a6 618
TASS Belgium NV 131:4758606c9316 619 static inline void startReadingBody(struct pico_http_client *client, struct pico_http_header *header)
tass 125:96003ae6f1d8 620 {
tass 125:96003ae6f1d8 621
TASS Belgium NV 131:4758606c9316 622 if(header->transferCoding == HTTP_TRANSFER_CHUNKED)
TASS Belgium NV 131:4758606c9316 623 {
TASS Belgium NV 131:4758606c9316 624 /* read the first chunk */
TASS Belgium NV 131:4758606c9316 625 header->contentLengthOrChunk = 0;
tass 125:96003ae6f1d8 626
TASS Belgium NV 131:4758606c9316 627 client->state = HTTP_READING_CHUNK_VALUE;
TASS Belgium NV 131:4758606c9316 628 readChunkLine(client);
tass 125:96003ae6f1d8 629
TASS Belgium NV 131:4758606c9316 630 }
TASS Belgium NV 131:4758606c9316 631 else
TASS Belgium NV 131:4758606c9316 632 client->state = HTTP_READING_BODY;
tass 125:96003ae6f1d8 633 }
tass 125:96003ae6f1d8 634
TASS Belgium NV 131:4758606c9316 635 static inline int parseLocAndCont(struct pico_http_client *client, struct pico_http_header *header, char *line, uint32_t *index)
tass 125:96003ae6f1d8 636 {
TASS Belgium NV 131:4758606c9316 637 char c;
TASS Belgium NV 131:4758606c9316 638 /* Location: */
tass 125:96003ae6f1d8 639
TASS Belgium NV 131:4758606c9316 640 if(isLocation(line))
TASS Belgium NV 131:4758606c9316 641 {
TASS Belgium NV 131:4758606c9316 642 *index = 0;
TASS Belgium NV 131:4758606c9316 643 while(consumeChar(c) > 0 && c != '\r')
TASS Belgium NV 131:4758606c9316 644 {
TASS Belgium NV 131:4758606c9316 645 line[(*index)++] = c;
TASS Belgium NV 131:4758606c9316 646 }
TASS Belgium NV 131:4758606c9316 647 /* allocate space for the field */
TASS Belgium NV 131:4758606c9316 648 header->location = pico_zalloc((*index) + 1u);
tass 125:96003ae6f1d8 649
TASS Belgium NV 131:4758606c9316 650 memcpy(header->location, line, (*index));
TASS Belgium NV 131:4758606c9316 651 return 1;
TASS Belgium NV 131:4758606c9316 652 } /* Content-Length: */
TASS Belgium NV 131:4758606c9316 653 else if(isContentLength(line))
TASS Belgium NV 131:4758606c9316 654 {
TASS Belgium NV 131:4758606c9316 655 header->contentLengthOrChunk = 0u;
TASS Belgium NV 131:4758606c9316 656 header->transferCoding = HTTP_TRANSFER_FULL;
TASS Belgium NV 131:4758606c9316 657 /* consume the first space */
TASS Belgium NV 131:4758606c9316 658 consumeChar(c);
TASS Belgium NV 131:4758606c9316 659 while(consumeChar(c) > 0 && c != '\r')
TASS Belgium NV 131:4758606c9316 660 {
TASS Belgium NV 131:4758606c9316 661 header->contentLengthOrChunk = header->contentLengthOrChunk * 10u + (uint32_t)(c - '0');
TASS Belgium NV 131:4758606c9316 662 }
TASS Belgium NV 131:4758606c9316 663 return 1;
TASS Belgium NV 131:4758606c9316 664 } /* Transfer-Encoding: chunked */
TASS Belgium NV 131:4758606c9316 665
TASS Belgium NV 131:4758606c9316 666 return 0;
tass 125:96003ae6f1d8 667 }
tass 125:96003ae6f1d8 668
TASS Belgium NV 131:4758606c9316 669 static inline int parseTransferEncoding(struct pico_http_client *client, struct pico_http_header *header, char *line, uint32_t *index)
tass 125:96003ae6f1d8 670 {
TASS Belgium NV 131:4758606c9316 671 char c;
tass 125:96003ae6f1d8 672
TASS Belgium NV 131:4758606c9316 673 if(isTransferEncoding(line))
TASS Belgium NV 131:4758606c9316 674 {
TASS Belgium NV 131:4758606c9316 675 (*index) = 0;
TASS Belgium NV 131:4758606c9316 676 while(consumeChar(c) > 0 && c != '\r')
TASS Belgium NV 131:4758606c9316 677 {
TASS Belgium NV 131:4758606c9316 678 line[(*index)++] = c;
TASS Belgium NV 131:4758606c9316 679 }
TASS Belgium NV 131:4758606c9316 680 if(isChunked(line))
TASS Belgium NV 131:4758606c9316 681 {
TASS Belgium NV 131:4758606c9316 682 header->contentLengthOrChunk = 0u;
TASS Belgium NV 131:4758606c9316 683 header->transferCoding = HTTP_TRANSFER_CHUNKED;
TASS Belgium NV 131:4758606c9316 684 }
tass 125:96003ae6f1d8 685
TASS Belgium NV 131:4758606c9316 686 return 1;
TASS Belgium NV 131:4758606c9316 687 } /* just ignore the line */
TASS Belgium NV 131:4758606c9316 688
TASS Belgium NV 131:4758606c9316 689 return 0;
tass 125:96003ae6f1d8 690 }
tass 125:96003ae6f1d8 691
tass 125:96003ae6f1d8 692
TASS Belgium NV 131:4758606c9316 693 static inline void parseFields(struct pico_http_client *client, struct pico_http_header *header, char *line, uint32_t *index)
tass 125:96003ae6f1d8 694 {
TASS Belgium NV 131:4758606c9316 695 char c;
tass 125:96003ae6f1d8 696
TASS Belgium NV 131:4758606c9316 697 if(!parseLocAndCont(client, header, line, index))
TASS Belgium NV 131:4758606c9316 698 {
TASS Belgium NV 131:4758606c9316 699 if(!parseTransferEncoding(client, header, line, index))
TASS Belgium NV 131:4758606c9316 700 {
TASS Belgium NV 131:4758606c9316 701 while(consumeChar(c) > 0 && c != '\r') nop();
TASS Belgium NV 131:4758606c9316 702 }
TASS Belgium NV 131:4758606c9316 703 }
tass 125:96003ae6f1d8 704
TASS Belgium NV 131:4758606c9316 705 /* consume the next one */
TASS Belgium NV 131:4758606c9316 706 consumeChar(c);
TASS Belgium NV 131:4758606c9316 707 /* reset the index */
TASS Belgium NV 131:4758606c9316 708 (*index) = 0u;
tass 125:96003ae6f1d8 709 }
tass 125:96003ae6f1d8 710
TASS Belgium NV 131:4758606c9316 711 static inline void parseRestOfHeader(struct pico_http_client *client, struct pico_http_header *header, char *line, uint32_t *index)
tass 125:96003ae6f1d8 712 {
TASS Belgium NV 131:4758606c9316 713 char c;
tass 125:96003ae6f1d8 714
TASS Belgium NV 131:4758606c9316 715 /* parse the rest of the header */
TASS Belgium NV 131:4758606c9316 716 while(consumeChar(c) > 0)
TASS Belgium NV 131:4758606c9316 717 {
TASS Belgium NV 131:4758606c9316 718 if(c == ':')
TASS Belgium NV 131:4758606c9316 719 {
TASS Belgium NV 131:4758606c9316 720 parseFields(client, header, line, index);
TASS Belgium NV 131:4758606c9316 721 }
TASS Belgium NV 131:4758606c9316 722 else if(c == '\r' && !(*index))
TASS Belgium NV 131:4758606c9316 723 {
TASS Belgium NV 131:4758606c9316 724 /* consume the \n */
TASS Belgium NV 131:4758606c9316 725 consumeChar(c);
TASS Belgium NV 131:4758606c9316 726 break;
TASS Belgium NV 131:4758606c9316 727 }
TASS Belgium NV 131:4758606c9316 728 else
TASS Belgium NV 131:4758606c9316 729 {
TASS Belgium NV 131:4758606c9316 730 line[(*index)++] = c;
TASS Belgium NV 131:4758606c9316 731 }
TASS Belgium NV 131:4758606c9316 732 }
tass 125:96003ae6f1d8 733 }
tass 125:96003ae6f1d8 734
TASS Belgium NV 131:4758606c9316 735 int parseHeaderFromServer(struct pico_http_client *client, struct pico_http_header *header)
tass 125:96003ae6f1d8 736 {
TASS Belgium NV 131:4758606c9316 737 char line[HTTP_HEADER_LINE_SIZE];
TASS Belgium NV 131:4758606c9316 738 uint32_t index = 0;
tass 125:96003ae6f1d8 739
TASS Belgium NV 131:4758606c9316 740 readFirstLine(client, line, &index);
TASS Belgium NV 131:4758606c9316 741 /* check the integrity of the response */
TASS Belgium NV 131:4758606c9316 742 /* make sure we have enough characters to include the response code */
TASS Belgium NV 131:4758606c9316 743 /* make sure the server response starts with HTTP/1. */
TASS Belgium NV 131:4758606c9316 744 if((index < RESPONSE_INDEX + 2u) || isNotHTTPv1(line))
TASS Belgium NV 131:4758606c9316 745 {
TASS Belgium NV 131:4758606c9316 746 /* wrong format of the the response */
TASS Belgium NV 131:4758606c9316 747 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 748 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 749 }
tass 68:0847e35d08a6 750
TASS Belgium NV 131:4758606c9316 751 /* extract response code */
TASS Belgium NV 131:4758606c9316 752 header->responseCode = (uint16_t)((line[RESPONSE_INDEX] - '0') * 100 +
TASS Belgium NV 131:4758606c9316 753 (line[RESPONSE_INDEX + 1] - '0') * 10 +
TASS Belgium NV 131:4758606c9316 754 (line[RESPONSE_INDEX + 2] - '0'));
tass 68:0847e35d08a6 755
TASS Belgium NV 131:4758606c9316 756 if(header->responseCode / 100u > 5u)
TASS Belgium NV 131:4758606c9316 757 {
TASS Belgium NV 131:4758606c9316 758 /* invalid response type */
TASS Belgium NV 131:4758606c9316 759 header->responseCode = 0;
TASS Belgium NV 131:4758606c9316 760 return HTTP_RETURN_ERROR;
TASS Belgium NV 131:4758606c9316 761 }
tass 68:0847e35d08a6 762
TASS Belgium NV 131:4758606c9316 763 dbg("Server response : %d \n", header->responseCode);
tass 68:0847e35d08a6 764
TASS Belgium NV 131:4758606c9316 765 parseRestOfHeader(client, header, line, &index);
tass 68:0847e35d08a6 766
TASS Belgium NV 131:4758606c9316 767 startReadingBody(client, header);
TASS Belgium NV 131:4758606c9316 768 dbg("End of header\n");
TASS Belgium NV 131:4758606c9316 769 return HTTP_RETURN_OK;
tass 68:0847e35d08a6 770
tass 68:0847e35d08a6 771 }
tass 68:0847e35d08a6 772
TASS Belgium NV 131:4758606c9316 773 /* an async read of the chunk part, since in theory a chunk can be split in 2 packets */
TASS Belgium NV 131:4758606c9316 774 static inline void setClientChunkState(struct pico_http_client *client)
tass 68:0847e35d08a6 775 {
tass 68:0847e35d08a6 776
TASS Belgium NV 131:4758606c9316 777 if(client->header->contentLengthOrChunk == 0 && client->state == HTTP_READING_BODY)
TASS Belgium NV 131:4758606c9316 778 {
TASS Belgium NV 131:4758606c9316 779 client->state = HTTP_READING_CHUNK_VALUE;
TASS Belgium NV 131:4758606c9316 780 }
tass 125:96003ae6f1d8 781 }
TASS Belgium NV 131:4758606c9316 782 static inline void readChunkTrail(struct pico_http_client *client)
tass 125:96003ae6f1d8 783 {
TASS Belgium NV 131:4758606c9316 784 char c;
tass 68:0847e35d08a6 785
TASS Belgium NV 131:4758606c9316 786 if(client->state == HTTP_READING_CHUNK_TRAIL)
TASS Belgium NV 131:4758606c9316 787 {
tass 125:96003ae6f1d8 788
TASS Belgium NV 131:4758606c9316 789 while(consumeChar(c) > 0 && c != '\n') nop();
TASS Belgium NV 131:4758606c9316 790 if(c == '\n') client->state = HTTP_READING_BODY;
TASS Belgium NV 131:4758606c9316 791 }
tass 125:96003ae6f1d8 792 }
TASS Belgium NV 131:4758606c9316 793 static inline void readChunkValue(struct pico_http_client *client)
tass 125:96003ae6f1d8 794 {
TASS Belgium NV 131:4758606c9316 795 char c;
tass 125:96003ae6f1d8 796
TASS Belgium NV 131:4758606c9316 797 while(consumeChar(c) > 0 && c != '\r' && c != ';')
TASS Belgium NV 131:4758606c9316 798 {
TASS Belgium NV 131:4758606c9316 799 if(is_hex_digit(c))
TASS Belgium NV 131:4758606c9316 800 client->header->contentLengthOrChunk = (client->header->contentLengthOrChunk << 4u) + (uint32_t)hex_digit_to_dec(c);
TASS Belgium NV 131:4758606c9316 801 }
TASS Belgium NV 131:4758606c9316 802 if(c == '\r' || c == ';') client->state = HTTP_READING_CHUNK_TRAIL;
tass 125:96003ae6f1d8 803 }
TASS Belgium NV 131:4758606c9316 804 int readChunkLine(struct pico_http_client *client)
tass 125:96003ae6f1d8 805 {
TASS Belgium NV 131:4758606c9316 806 setClientChunkState(client);
tass 125:96003ae6f1d8 807
TASS Belgium NV 131:4758606c9316 808 if(client->state == HTTP_READING_CHUNK_VALUE)
TASS Belgium NV 131:4758606c9316 809 {
TASS Belgium NV 131:4758606c9316 810 readChunkValue(client);
TASS Belgium NV 131:4758606c9316 811 }
tass 68:0847e35d08a6 812
TASS Belgium NV 131:4758606c9316 813 readChunkTrail(client);
TASS Belgium NV 131:4758606c9316 814
TASS Belgium NV 131:4758606c9316 815 return HTTP_RETURN_OK;
tass 68:0847e35d08a6 816 }
tass 68:0847e35d08a6 817 #endif