CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2

Dependents:   USBEthernet_TEST

Fork of USB_Ethernet by Daniele Lacamera

Committer:
daniele
Date:
Sat Aug 03 13:16:14 2013 +0000
Revision:
2:540f6e142d59
Moved to single package

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 2:540f6e142d59 1 /*********************************************************************
daniele 2:540f6e142d59 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 2:540f6e142d59 3 See LICENSE and COPYING for usage.
daniele 2:540f6e142d59 4
daniele 2:540f6e142d59 5 Author: Andrei Carp <andrei.carp@tass.be>
daniele 2:540f6e142d59 6 *********************************************************************/
daniele 2:540f6e142d59 7
daniele 2:540f6e142d59 8 #include "pico_stack.h"
daniele 2:540f6e142d59 9 #include "pico_http_server.h"
daniele 2:540f6e142d59 10 #include "pico_tcp.h"
daniele 2:540f6e142d59 11 #include "pico_tree.h"
daniele 2:540f6e142d59 12 #include "pico_socket.h"
daniele 2:540f6e142d59 13
daniele 2:540f6e142d59 14 #ifdef PICO_SUPPORT_HTTP_SERVER
daniele 2:540f6e142d59 15
daniele 2:540f6e142d59 16 #define BACKLOG 10
daniele 2:540f6e142d59 17
daniele 2:540f6e142d59 18 #define HTTP_SERVER_CLOSED 0
daniele 2:540f6e142d59 19 #define HTTP_SERVER_LISTEN 1
daniele 2:540f6e142d59 20
daniele 2:540f6e142d59 21 #define HTTP_HEADER_MAX_LINE 256u
daniele 2:540f6e142d59 22
daniele 2:540f6e142d59 23 #define consumeChar(c) (pico_socket_read(client->sck,&c,1u))
daniele 2:540f6e142d59 24
daniele 2:540f6e142d59 25 static char returnOkHeader[] =
daniele 2:540f6e142d59 26 "HTTP/1.1 200 OK\r\n\
daniele 2:540f6e142d59 27 Host: localhost\r\n\
daniele 2:540f6e142d59 28 Transfer-Encoding: chunked\r\n\
daniele 2:540f6e142d59 29 Connection: close\r\n\
daniele 2:540f6e142d59 30 \r\n";
daniele 2:540f6e142d59 31
daniele 2:540f6e142d59 32 static char returnFailHeader[] =
daniele 2:540f6e142d59 33 "HTTP/1.1 404 Not Found\r\n\
daniele 2:540f6e142d59 34 Host: localhost\r\n\
daniele 2:540f6e142d59 35 Connection: close\r\n\
daniele 2:540f6e142d59 36 \r\n\
daniele 2:540f6e142d59 37 <html><body>The resource you requested cannot be found !</body></html>";
daniele 2:540f6e142d59 38
daniele 2:540f6e142d59 39 static char errorHeader[] =
daniele 2:540f6e142d59 40 "HTTP/1.1 400 Bad Request\r\n\
daniele 2:540f6e142d59 41 Host: localhost\r\n\
daniele 2:540f6e142d59 42 Connection: close\r\n\
daniele 2:540f6e142d59 43 \r\n\
daniele 2:540f6e142d59 44 <html><body>There was a problem with your request !</body></html>";
daniele 2:540f6e142d59 45
daniele 2:540f6e142d59 46 struct httpServer
daniele 2:540f6e142d59 47 {
daniele 2:540f6e142d59 48 uint16_t state;
daniele 2:540f6e142d59 49 struct pico_socket * sck;
daniele 2:540f6e142d59 50 uint16_t port;
daniele 2:540f6e142d59 51 void (*wakeup)(uint16_t ev, uint16_t param);
daniele 2:540f6e142d59 52 uint8_t accepted;
daniele 2:540f6e142d59 53 };
daniele 2:540f6e142d59 54
daniele 2:540f6e142d59 55 struct httpClient
daniele 2:540f6e142d59 56 {
daniele 2:540f6e142d59 57 uint16_t connectionID;
daniele 2:540f6e142d59 58 struct pico_socket * sck;
daniele 2:540f6e142d59 59 void * buffer;
daniele 2:540f6e142d59 60 uint16_t bufferSize;
daniele 2:540f6e142d59 61 uint16_t bufferSent;
daniele 2:540f6e142d59 62 char * resource;
daniele 2:540f6e142d59 63 uint16_t state;
daniele 2:540f6e142d59 64 };
daniele 2:540f6e142d59 65
daniele 2:540f6e142d59 66 /* Local states for clients */
daniele 2:540f6e142d59 67 #define HTTP_WAIT_HDR 0
daniele 2:540f6e142d59 68 #define HTTP_WAIT_EOF_HDR 1
daniele 2:540f6e142d59 69 #define HTTP_EOF_HDR 2
daniele 2:540f6e142d59 70 #define HTTP_WAIT_RESPONSE 3
daniele 2:540f6e142d59 71 #define HTTP_WAIT_DATA 4
daniele 2:540f6e142d59 72 #define HTTP_SENDING_DATA 5
daniele 2:540f6e142d59 73 #define HTTP_ERROR 6
daniele 2:540f6e142d59 74 #define HTTP_CLOSED 7
daniele 2:540f6e142d59 75
daniele 2:540f6e142d59 76 static struct httpServer server = {};
daniele 2:540f6e142d59 77
daniele 2:540f6e142d59 78 /*
daniele 2:540f6e142d59 79 * Private functions
daniele 2:540f6e142d59 80 */
daniele 2:540f6e142d59 81 static int parseRequest(struct httpClient * client);
daniele 2:540f6e142d59 82 static int readRemainingHeader(struct httpClient * client);
daniele 2:540f6e142d59 83 static void sendData(struct httpClient * client);
daniele 2:540f6e142d59 84 static inline int readData(struct httpClient * client); // used only in a place
daniele 2:540f6e142d59 85 static inline struct httpClient * findClient(uint16_t conn);
daniele 2:540f6e142d59 86
daniele 2:540f6e142d59 87 static int compareClients(void * ka, void * kb)
daniele 2:540f6e142d59 88 {
daniele 2:540f6e142d59 89 return ((struct httpClient *)ka)->connectionID - ((struct httpClient *)kb)->connectionID;
daniele 2:540f6e142d59 90 }
daniele 2:540f6e142d59 91
daniele 2:540f6e142d59 92 PICO_TREE_DECLARE(pico_http_clients,compareClients);
daniele 2:540f6e142d59 93
daniele 2:540f6e142d59 94 void httpServerCbk(uint16_t ev, struct pico_socket *s)
daniele 2:540f6e142d59 95 {
daniele 2:540f6e142d59 96 struct pico_tree_node * index;
daniele 2:540f6e142d59 97 struct httpClient * client = NULL;
daniele 2:540f6e142d59 98 uint8_t serverEvent = FALSE;
daniele 2:540f6e142d59 99
daniele 2:540f6e142d59 100 // determine the client for the socket
daniele 2:540f6e142d59 101 if( s == server.sck)
daniele 2:540f6e142d59 102 {
daniele 2:540f6e142d59 103 serverEvent = TRUE;
daniele 2:540f6e142d59 104 }
daniele 2:540f6e142d59 105 else
daniele 2:540f6e142d59 106 {
daniele 2:540f6e142d59 107 pico_tree_foreach(index,&pico_http_clients)
daniele 2:540f6e142d59 108 {
daniele 2:540f6e142d59 109 client = index->keyValue;
daniele 2:540f6e142d59 110 if(client->sck == s) break;
daniele 2:540f6e142d59 111 client = NULL;
daniele 2:540f6e142d59 112 }
daniele 2:540f6e142d59 113 }
daniele 2:540f6e142d59 114
daniele 2:540f6e142d59 115 if(!client && !serverEvent)
daniele 2:540f6e142d59 116 {
daniele 2:540f6e142d59 117 return;
daniele 2:540f6e142d59 118 }
daniele 2:540f6e142d59 119
daniele 2:540f6e142d59 120 if (ev & PICO_SOCK_EV_RD)
daniele 2:540f6e142d59 121 {
daniele 2:540f6e142d59 122
daniele 2:540f6e142d59 123 if(readData(client) == HTTP_RETURN_ERROR)
daniele 2:540f6e142d59 124 {
daniele 2:540f6e142d59 125 // send out error
daniele 2:540f6e142d59 126 client->state = HTTP_ERROR;
daniele 2:540f6e142d59 127 pico_socket_write(client->sck,errorHeader,sizeof(errorHeader)-1);
daniele 2:540f6e142d59 128 server.wakeup(EV_HTTP_ERROR,client->connectionID);
daniele 2:540f6e142d59 129 }
daniele 2:540f6e142d59 130 }
daniele 2:540f6e142d59 131
daniele 2:540f6e142d59 132 if(ev & PICO_SOCK_EV_WR)
daniele 2:540f6e142d59 133 {
daniele 2:540f6e142d59 134 if(client->state == HTTP_SENDING_DATA)
daniele 2:540f6e142d59 135 {
daniele 2:540f6e142d59 136 sendData(client);
daniele 2:540f6e142d59 137 }
daniele 2:540f6e142d59 138 }
daniele 2:540f6e142d59 139
daniele 2:540f6e142d59 140 if(ev & PICO_SOCK_EV_CONN)
daniele 2:540f6e142d59 141 {
daniele 2:540f6e142d59 142 server.accepted = FALSE;
daniele 2:540f6e142d59 143 server.wakeup(EV_HTTP_CON,HTTP_SERVER_ID);
daniele 2:540f6e142d59 144 if(!server.accepted)
daniele 2:540f6e142d59 145 {
daniele 2:540f6e142d59 146 pico_socket_close(s); // reject socket
daniele 2:540f6e142d59 147 }
daniele 2:540f6e142d59 148 }
daniele 2:540f6e142d59 149
daniele 2:540f6e142d59 150 if( (ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN) )
daniele 2:540f6e142d59 151 {
daniele 2:540f6e142d59 152 server.wakeup(EV_HTTP_CLOSE,(serverEvent ? HTTP_SERVER_ID : client->connectionID));
daniele 2:540f6e142d59 153 }
daniele 2:540f6e142d59 154
daniele 2:540f6e142d59 155 if(ev & PICO_SOCK_EV_ERR)
daniele 2:540f6e142d59 156 {
daniele 2:540f6e142d59 157 server.wakeup(EV_HTTP_ERROR,(serverEvent ? HTTP_SERVER_ID : client->connectionID));
daniele 2:540f6e142d59 158 }
daniele 2:540f6e142d59 159 }
daniele 2:540f6e142d59 160
daniele 2:540f6e142d59 161 /*
daniele 2:540f6e142d59 162 * API for starting the server. If 0 is passed as a port, the port 80
daniele 2:540f6e142d59 163 * will be used.
daniele 2:540f6e142d59 164 */
daniele 2:540f6e142d59 165 int pico_http_server_start(uint16_t port, void (*wakeup)(uint16_t ev, uint16_t conn))
daniele 2:540f6e142d59 166 {
daniele 2:540f6e142d59 167 struct pico_ip4 anything = {};
daniele 2:540f6e142d59 168
daniele 2:540f6e142d59 169 server.port = port ? short_be(port) : short_be(80u);
daniele 2:540f6e142d59 170
daniele 2:540f6e142d59 171 if(!wakeup)
daniele 2:540f6e142d59 172 {
daniele 2:540f6e142d59 173 pico_err = PICO_ERR_EINVAL;
daniele 2:540f6e142d59 174 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 175 }
daniele 2:540f6e142d59 176
daniele 2:540f6e142d59 177 server.sck = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &httpServerCbk);
daniele 2:540f6e142d59 178
daniele 2:540f6e142d59 179 if(!server.sck)
daniele 2:540f6e142d59 180 {
daniele 2:540f6e142d59 181 pico_err = PICO_ERR_EFAULT;
daniele 2:540f6e142d59 182 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 183 }
daniele 2:540f6e142d59 184
daniele 2:540f6e142d59 185 if(pico_socket_bind(server.sck , &anything, &server.port)!=0)
daniele 2:540f6e142d59 186 {
daniele 2:540f6e142d59 187 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 2:540f6e142d59 188 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 189 }
daniele 2:540f6e142d59 190
daniele 2:540f6e142d59 191 if (pico_socket_listen(server.sck, BACKLOG) != 0)
daniele 2:540f6e142d59 192 {
daniele 2:540f6e142d59 193 pico_err = PICO_ERR_EADDRINUSE;
daniele 2:540f6e142d59 194 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 195 }
daniele 2:540f6e142d59 196 server.wakeup = wakeup;
daniele 2:540f6e142d59 197 server.state = HTTP_SERVER_LISTEN;
daniele 2:540f6e142d59 198 return HTTP_RETURN_OK;
daniele 2:540f6e142d59 199 }
daniele 2:540f6e142d59 200
daniele 2:540f6e142d59 201 /*
daniele 2:540f6e142d59 202 * API for accepting new connections. This function should be
daniele 2:540f6e142d59 203 * called when the event EV_HTTP_CON is triggered, if not called
daniele 2:540f6e142d59 204 * when noticed the connection will be considered rejected and the
daniele 2:540f6e142d59 205 * socket will be dropped.
daniele 2:540f6e142d59 206 *
daniele 2:540f6e142d59 207 * Returns the ID of the new connection or a negative value if error.
daniele 2:540f6e142d59 208 */
daniele 2:540f6e142d59 209 int pico_http_server_accept(void)
daniele 2:540f6e142d59 210 {
daniele 2:540f6e142d59 211 struct pico_ip4 orig;
daniele 2:540f6e142d59 212 struct httpClient * client;
daniele 2:540f6e142d59 213 uint16_t port;
daniele 2:540f6e142d59 214
daniele 2:540f6e142d59 215 client = pico_zalloc(sizeof(struct httpClient));
daniele 2:540f6e142d59 216 if(!client)
daniele 2:540f6e142d59 217 {
daniele 2:540f6e142d59 218 pico_err = PICO_ERR_ENOMEM;
daniele 2:540f6e142d59 219 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 220 }
daniele 2:540f6e142d59 221
daniele 2:540f6e142d59 222 client->sck = pico_socket_accept(server.sck,&orig,&port);
daniele 2:540f6e142d59 223
daniele 2:540f6e142d59 224 if(!client->sck)
daniele 2:540f6e142d59 225 {
daniele 2:540f6e142d59 226 pico_err = PICO_ERR_ENOMEM;
daniele 2:540f6e142d59 227 pico_free(client);
daniele 2:540f6e142d59 228 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 229 }
daniele 2:540f6e142d59 230
daniele 2:540f6e142d59 231 server.accepted = TRUE;
daniele 2:540f6e142d59 232 // buffer used for async sending
daniele 2:540f6e142d59 233 client->state = HTTP_WAIT_HDR;
daniele 2:540f6e142d59 234 client->buffer = NULL;
daniele 2:540f6e142d59 235 client->bufferSize = 0;
daniele 2:540f6e142d59 236 client->connectionID = pico_rand() & 0x7FFF;
daniele 2:540f6e142d59 237
daniele 2:540f6e142d59 238 //add element to the tree, if duplicate because the rand
daniele 2:540f6e142d59 239 //regenerate
daniele 2:540f6e142d59 240 while(pico_tree_insert(&pico_http_clients,client)!=NULL)
daniele 2:540f6e142d59 241 client->connectionID = pico_rand() & 0x7FFF;
daniele 2:540f6e142d59 242
daniele 2:540f6e142d59 243 return client->connectionID;
daniele 2:540f6e142d59 244 }
daniele 2:540f6e142d59 245
daniele 2:540f6e142d59 246 /*
daniele 2:540f6e142d59 247 * Function used for getting the resource asked by the
daniele 2:540f6e142d59 248 * client. It is useful after the request header (EV_HTTP_REQ)
daniele 2:540f6e142d59 249 * from client was received, otherwise NULL is returned.
daniele 2:540f6e142d59 250 */
daniele 2:540f6e142d59 251 char * pico_http_getResource(uint16_t conn)
daniele 2:540f6e142d59 252 {
daniele 2:540f6e142d59 253 struct httpClient * client = findClient(conn);
daniele 2:540f6e142d59 254
daniele 2:540f6e142d59 255 if(!client)
daniele 2:540f6e142d59 256 return NULL;
daniele 2:540f6e142d59 257 else
daniele 2:540f6e142d59 258 return client->resource;
daniele 2:540f6e142d59 259 }
daniele 2:540f6e142d59 260
daniele 2:540f6e142d59 261 /*
daniele 2:540f6e142d59 262 * After the resource was asked by the client (EV_HTTP_REQ)
daniele 2:540f6e142d59 263 * before doing anything else, the server has to let know
daniele 2:540f6e142d59 264 * the client if the resource can be provided or not.
daniele 2:540f6e142d59 265 *
daniele 2:540f6e142d59 266 * This is controlled via the code parameter which can
daniele 2:540f6e142d59 267 * have two values :
daniele 2:540f6e142d59 268 *
daniele 2:540f6e142d59 269 * HTTP_RESOURCE_FOUND or HTTP_RESOURCE_NOT_FOUND
daniele 2:540f6e142d59 270 *
daniele 2:540f6e142d59 271 * If a resource is reported not found the 404 header will be sent and the connection
daniele 2:540f6e142d59 272 * will be closed , otherwise the 200 header is sent and the user should
daniele 2:540f6e142d59 273 * immediately submit data.
daniele 2:540f6e142d59 274 *
daniele 2:540f6e142d59 275 */
daniele 2:540f6e142d59 276 int pico_http_respond(uint16_t conn, uint16_t code)
daniele 2:540f6e142d59 277 {
daniele 2:540f6e142d59 278 struct httpClient * client = findClient(conn);
daniele 2:540f6e142d59 279
daniele 2:540f6e142d59 280 if(!client)
daniele 2:540f6e142d59 281 {
daniele 2:540f6e142d59 282 dbg("Client not found !\n");
daniele 2:540f6e142d59 283 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 284 }
daniele 2:540f6e142d59 285
daniele 2:540f6e142d59 286 if(client->state == HTTP_WAIT_RESPONSE)
daniele 2:540f6e142d59 287 {
daniele 2:540f6e142d59 288 if(code == HTTP_RESOURCE_FOUND)
daniele 2:540f6e142d59 289 {
daniele 2:540f6e142d59 290 client->state = HTTP_WAIT_DATA;
daniele 2:540f6e142d59 291 return pico_socket_write(client->sck,returnOkHeader,sizeof(returnOkHeader)-1);//remove \0
daniele 2:540f6e142d59 292 }
daniele 2:540f6e142d59 293 else
daniele 2:540f6e142d59 294 {
daniele 2:540f6e142d59 295 int length;
daniele 2:540f6e142d59 296
daniele 2:540f6e142d59 297 length = pico_socket_write(client->sck,returnFailHeader,sizeof(returnFailHeader)-1);//remove \0
daniele 2:540f6e142d59 298 pico_socket_close(client->sck);
daniele 2:540f6e142d59 299 client->state = HTTP_CLOSED;
daniele 2:540f6e142d59 300 return length;
daniele 2:540f6e142d59 301
daniele 2:540f6e142d59 302 }
daniele 2:540f6e142d59 303 }
daniele 2:540f6e142d59 304 else
daniele 2:540f6e142d59 305 {
daniele 2:540f6e142d59 306 dbg("Bad state for the client \n");
daniele 2:540f6e142d59 307 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 308 }
daniele 2:540f6e142d59 309
daniele 2:540f6e142d59 310 }
daniele 2:540f6e142d59 311
daniele 2:540f6e142d59 312 /*
daniele 2:540f6e142d59 313 * API used to submit data to the client.
daniele 2:540f6e142d59 314 * Server sends data only using Transfer-Encoding: chunked.
daniele 2:540f6e142d59 315 *
daniele 2:540f6e142d59 316 * With this function the user will submit a data chunk to
daniele 2:540f6e142d59 317 * be sent.
daniele 2:540f6e142d59 318 * The function will send the chunk size in hex and the rest will
daniele 2:540f6e142d59 319 * be sent using WR event from sockets.
daniele 2:540f6e142d59 320 * After each transmision EV_HTTP_PROGRESS is called and at the
daniele 2:540f6e142d59 321 * end of the chunk EV_HTTP_SENT is called.
daniele 2:540f6e142d59 322 *
daniele 2:540f6e142d59 323 * To let the client know this is the last chunk, the user
daniele 2:540f6e142d59 324 * should pass a NULL buffer.
daniele 2:540f6e142d59 325 */
daniele 2:540f6e142d59 326 int pico_http_submitData(uint16_t conn, void * buffer, int len)
daniele 2:540f6e142d59 327 {
daniele 2:540f6e142d59 328
daniele 2:540f6e142d59 329 struct httpClient * client = findClient(conn);
daniele 2:540f6e142d59 330 char chunkStr[10];
daniele 2:540f6e142d59 331 int chunkCount;
daniele 2:540f6e142d59 332
daniele 2:540f6e142d59 333 if(client->state != HTTP_WAIT_DATA)
daniele 2:540f6e142d59 334 {
daniele 2:540f6e142d59 335 dbg("Client is in a different state than accepted\n");
daniele 2:540f6e142d59 336 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 337 }
daniele 2:540f6e142d59 338
daniele 2:540f6e142d59 339 if(client->buffer)
daniele 2:540f6e142d59 340 {
daniele 2:540f6e142d59 341 dbg("Already a buffer submited\n");
daniele 2:540f6e142d59 342 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 343 }
daniele 2:540f6e142d59 344
daniele 2:540f6e142d59 345 if(!client)
daniele 2:540f6e142d59 346 {
daniele 2:540f6e142d59 347 dbg("Wrong connection ID\n");
daniele 2:540f6e142d59 348 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 349 }
daniele 2:540f6e142d59 350
daniele 2:540f6e142d59 351 if(!buffer)
daniele 2:540f6e142d59 352 {
daniele 2:540f6e142d59 353 len = 0;
daniele 2:540f6e142d59 354 }
daniele 2:540f6e142d59 355
daniele 2:540f6e142d59 356 if(len > 0)
daniele 2:540f6e142d59 357 {
daniele 2:540f6e142d59 358 client->buffer = pico_zalloc(len);
daniele 2:540f6e142d59 359 if(!client->buffer)
daniele 2:540f6e142d59 360 {
daniele 2:540f6e142d59 361 pico_err = PICO_ERR_ENOMEM;
daniele 2:540f6e142d59 362 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 363 }
daniele 2:540f6e142d59 364 // taking over the buffer
daniele 2:540f6e142d59 365 memcpy(client->buffer,buffer,len);
daniele 2:540f6e142d59 366 }
daniele 2:540f6e142d59 367 else
daniele 2:540f6e142d59 368 client->buffer = NULL;
daniele 2:540f6e142d59 369
daniele 2:540f6e142d59 370
daniele 2:540f6e142d59 371 client->bufferSize = len;
daniele 2:540f6e142d59 372 client->bufferSent = 0;
daniele 2:540f6e142d59 373
daniele 2:540f6e142d59 374 // create the chunk size and send it
daniele 2:540f6e142d59 375 if(len > 0)
daniele 2:540f6e142d59 376 {
daniele 2:540f6e142d59 377 client->state = HTTP_SENDING_DATA;
daniele 2:540f6e142d59 378 chunkCount = pico_itoaHex(client->bufferSize,chunkStr);
daniele 2:540f6e142d59 379 chunkStr[chunkCount++] = '\r';
daniele 2:540f6e142d59 380 chunkStr[chunkCount++] = '\n';
daniele 2:540f6e142d59 381 pico_socket_write(client->sck,chunkStr,chunkCount);
daniele 2:540f6e142d59 382 }
daniele 2:540f6e142d59 383 else if(len == 0)
daniele 2:540f6e142d59 384 {
daniele 2:540f6e142d59 385 dbg("->\n");
daniele 2:540f6e142d59 386 // end of transmision
daniele 2:540f6e142d59 387 pico_socket_write(client->sck,"0\r\n\r\n",5u);
daniele 2:540f6e142d59 388 // nothing left, close the client
daniele 2:540f6e142d59 389 pico_socket_close(client->sck);
daniele 2:540f6e142d59 390 client->state = HTTP_CLOSED;
daniele 2:540f6e142d59 391 }
daniele 2:540f6e142d59 392
daniele 2:540f6e142d59 393 return HTTP_RETURN_OK;
daniele 2:540f6e142d59 394 }
daniele 2:540f6e142d59 395
daniele 2:540f6e142d59 396 /*
daniele 2:540f6e142d59 397 * When EV_HTTP_PROGRESS is triggered you can use this
daniele 2:540f6e142d59 398 * function to check the state of the chunk.
daniele 2:540f6e142d59 399 */
daniele 2:540f6e142d59 400
daniele 2:540f6e142d59 401 int pico_http_getProgress(uint16_t conn, uint16_t * sent, uint16_t *total)
daniele 2:540f6e142d59 402 {
daniele 2:540f6e142d59 403 struct httpClient * client = findClient(conn);
daniele 2:540f6e142d59 404
daniele 2:540f6e142d59 405 if(!client)
daniele 2:540f6e142d59 406 {
daniele 2:540f6e142d59 407 dbg("Wrong connection id !\n");
daniele 2:540f6e142d59 408 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 409 }
daniele 2:540f6e142d59 410
daniele 2:540f6e142d59 411 *sent = client->bufferSent;
daniele 2:540f6e142d59 412 *total = client->bufferSize;
daniele 2:540f6e142d59 413
daniele 2:540f6e142d59 414 return HTTP_RETURN_OK;
daniele 2:540f6e142d59 415 }
daniele 2:540f6e142d59 416
daniele 2:540f6e142d59 417 /*
daniele 2:540f6e142d59 418 * This API can be used to close either a client
daniele 2:540f6e142d59 419 * or the server ( if you pass HTTP_SERVER_ID as a connection ID).
daniele 2:540f6e142d59 420 */
daniele 2:540f6e142d59 421 int pico_http_close(uint16_t conn)
daniele 2:540f6e142d59 422 {
daniele 2:540f6e142d59 423 // close the server
daniele 2:540f6e142d59 424 if(conn == HTTP_SERVER_ID)
daniele 2:540f6e142d59 425 {
daniele 2:540f6e142d59 426 if(server.state == HTTP_SERVER_LISTEN)
daniele 2:540f6e142d59 427 {
daniele 2:540f6e142d59 428 struct pico_tree_node * index, * tmp;
daniele 2:540f6e142d59 429 // close the server
daniele 2:540f6e142d59 430 pico_socket_close(server.sck);
daniele 2:540f6e142d59 431 server.sck = NULL;
daniele 2:540f6e142d59 432
daniele 2:540f6e142d59 433 // destroy the tree
daniele 2:540f6e142d59 434 pico_tree_foreach_safe(index,&pico_http_clients,tmp)
daniele 2:540f6e142d59 435 {
daniele 2:540f6e142d59 436 struct httpClient * client = index->keyValue;
daniele 2:540f6e142d59 437
daniele 2:540f6e142d59 438 if(client->resource)
daniele 2:540f6e142d59 439 pico_free(client->resource);
daniele 2:540f6e142d59 440
daniele 2:540f6e142d59 441 pico_socket_close(client->sck);
daniele 2:540f6e142d59 442 pico_tree_delete(&pico_http_clients,client);
daniele 2:540f6e142d59 443 }
daniele 2:540f6e142d59 444
daniele 2:540f6e142d59 445 server.state = HTTP_SERVER_CLOSED;
daniele 2:540f6e142d59 446 return HTTP_RETURN_OK;
daniele 2:540f6e142d59 447 }
daniele 2:540f6e142d59 448 else // nothing to close
daniele 2:540f6e142d59 449 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 450 } // close a connection in this case
daniele 2:540f6e142d59 451 else
daniele 2:540f6e142d59 452 {
daniele 2:540f6e142d59 453
daniele 2:540f6e142d59 454 struct httpClient * client = findClient(conn);
daniele 2:540f6e142d59 455
daniele 2:540f6e142d59 456 if(!client)
daniele 2:540f6e142d59 457 {
daniele 2:540f6e142d59 458 dbg("Client not found..\n");
daniele 2:540f6e142d59 459 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 460 }
daniele 2:540f6e142d59 461
daniele 2:540f6e142d59 462 pico_tree_delete(&pico_http_clients,client);
daniele 2:540f6e142d59 463
daniele 2:540f6e142d59 464 if(client->resource)
daniele 2:540f6e142d59 465 pico_free(client->resource);
daniele 2:540f6e142d59 466
daniele 2:540f6e142d59 467 if(client->buffer)
daniele 2:540f6e142d59 468 pico_free(client->buffer);
daniele 2:540f6e142d59 469
daniele 2:540f6e142d59 470 if(client->state != HTTP_CLOSED || !client->sck)
daniele 2:540f6e142d59 471 pico_socket_close(client->sck);
daniele 2:540f6e142d59 472
daniele 2:540f6e142d59 473 pico_free(client);
daniele 2:540f6e142d59 474 return HTTP_RETURN_OK;
daniele 2:540f6e142d59 475 }
daniele 2:540f6e142d59 476 }
daniele 2:540f6e142d59 477
daniele 2:540f6e142d59 478 // check the integrity of the request
daniele 2:540f6e142d59 479 int parseRequest(struct httpClient * client)
daniele 2:540f6e142d59 480 {
daniele 2:540f6e142d59 481 char c;
daniele 2:540f6e142d59 482 //read first line
daniele 2:540f6e142d59 483 consumeChar(c);
daniele 2:540f6e142d59 484 if(c == 'G')
daniele 2:540f6e142d59 485 { // possible GET
daniele 2:540f6e142d59 486
daniele 2:540f6e142d59 487 char line[HTTP_HEADER_MAX_LINE];
daniele 2:540f6e142d59 488 int index = 0;
daniele 2:540f6e142d59 489
daniele 2:540f6e142d59 490 line[index] = c;
daniele 2:540f6e142d59 491
daniele 2:540f6e142d59 492 // consume the full line
daniele 2:540f6e142d59 493 while(consumeChar(c)>0) // read char by char only the first line
daniele 2:540f6e142d59 494 {
daniele 2:540f6e142d59 495 line[++index] = c;
daniele 2:540f6e142d59 496 if(c == '\n')
daniele 2:540f6e142d59 497 break;
daniele 2:540f6e142d59 498
daniele 2:540f6e142d59 499 if(index >= HTTP_HEADER_MAX_LINE)
daniele 2:540f6e142d59 500 {
daniele 2:540f6e142d59 501 dbg("Size exceeded \n");
daniele 2:540f6e142d59 502 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 503 }
daniele 2:540f6e142d59 504 }
daniele 2:540f6e142d59 505
daniele 2:540f6e142d59 506 // extract the function and the resource
daniele 2:540f6e142d59 507 if(memcmp(line,"GET",3u) || line[3u]!=' ' || index < 10u || line[index] !='\n')
daniele 2:540f6e142d59 508 {
daniele 2:540f6e142d59 509 dbg("Wrong command or wrong ending\n");
daniele 2:540f6e142d59 510 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 511 }
daniele 2:540f6e142d59 512
daniele 2:540f6e142d59 513 // start reading the resource
daniele 2:540f6e142d59 514 index = 4u; // go after ' '
daniele 2:540f6e142d59 515 while(line[index]!=' ')
daniele 2:540f6e142d59 516 {
daniele 2:540f6e142d59 517 if(line[index]=='\n') // no terminator ' '
daniele 2:540f6e142d59 518 {
daniele 2:540f6e142d59 519 dbg("No terminator...\n");
daniele 2:540f6e142d59 520 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 521 }
daniele 2:540f6e142d59 522
daniele 2:540f6e142d59 523 index++;
daniele 2:540f6e142d59 524 }
daniele 2:540f6e142d59 525
daniele 2:540f6e142d59 526 client->resource = pico_zalloc(index - 3u);// allocate without the GET in front + 1 which is \0
daniele 2:540f6e142d59 527
daniele 2:540f6e142d59 528 if(!client)
daniele 2:540f6e142d59 529 {
daniele 2:540f6e142d59 530 pico_err = PICO_ERR_ENOMEM;
daniele 2:540f6e142d59 531 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 532 }
daniele 2:540f6e142d59 533
daniele 2:540f6e142d59 534 // copy the resource
daniele 2:540f6e142d59 535 memcpy(client->resource,line+4u,index-4u);// copy without the \0 which was already set by pico_zalloc
daniele 2:540f6e142d59 536
daniele 2:540f6e142d59 537 client->state = HTTP_WAIT_EOF_HDR;
daniele 2:540f6e142d59 538 return HTTP_RETURN_OK;
daniele 2:540f6e142d59 539
daniele 2:540f6e142d59 540 }
daniele 2:540f6e142d59 541
daniele 2:540f6e142d59 542 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 543 }
daniele 2:540f6e142d59 544
daniele 2:540f6e142d59 545
daniele 2:540f6e142d59 546
daniele 2:540f6e142d59 547 int readRemainingHeader(struct httpClient * client)
daniele 2:540f6e142d59 548 {
daniele 2:540f6e142d59 549 char line[100];
daniele 2:540f6e142d59 550 int count = 0;
daniele 2:540f6e142d59 551 int len;
daniele 2:540f6e142d59 552
daniele 2:540f6e142d59 553 while( (len = pico_socket_read(client->sck,line,100u)) > 0)
daniele 2:540f6e142d59 554 {
daniele 2:540f6e142d59 555 char c;
daniele 2:540f6e142d59 556 int index = 0;
daniele 2:540f6e142d59 557 // parse the response
daniele 2:540f6e142d59 558 while(index < len)
daniele 2:540f6e142d59 559 {
daniele 2:540f6e142d59 560 c = line[index++];
daniele 2:540f6e142d59 561 if(c!='\r' && c!='\n')
daniele 2:540f6e142d59 562 count++;
daniele 2:540f6e142d59 563 if(c=='\n')
daniele 2:540f6e142d59 564 {
daniele 2:540f6e142d59 565 if(!count)
daniele 2:540f6e142d59 566 {
daniele 2:540f6e142d59 567 client->state = HTTP_EOF_HDR;
daniele 2:540f6e142d59 568 dbg("End of header !\n");
daniele 2:540f6e142d59 569 break;
daniele 2:540f6e142d59 570 }
daniele 2:540f6e142d59 571 count = 0;
daniele 2:540f6e142d59 572
daniele 2:540f6e142d59 573 }
daniele 2:540f6e142d59 574 }
daniele 2:540f6e142d59 575 }
daniele 2:540f6e142d59 576
daniele 2:540f6e142d59 577 return HTTP_RETURN_OK;
daniele 2:540f6e142d59 578 }
daniele 2:540f6e142d59 579
daniele 2:540f6e142d59 580 void sendData(struct httpClient * client)
daniele 2:540f6e142d59 581 {
daniele 2:540f6e142d59 582 int length;
daniele 2:540f6e142d59 583 while( client->bufferSent < client->bufferSize &&
daniele 2:540f6e142d59 584 (length = pico_socket_write(client->sck,client->buffer+client->bufferSent,client->bufferSize-client->bufferSent)) > 0 )
daniele 2:540f6e142d59 585 {
daniele 2:540f6e142d59 586 client->bufferSent += length;
daniele 2:540f6e142d59 587 server.wakeup(EV_HTTP_PROGRESS,client->connectionID);
daniele 2:540f6e142d59 588 }
daniele 2:540f6e142d59 589
daniele 2:540f6e142d59 590 if(client->bufferSent == client->bufferSize && client->bufferSize)
daniele 2:540f6e142d59 591 {
daniele 2:540f6e142d59 592 //send chunk trail
daniele 2:540f6e142d59 593 if(pico_socket_write(client->sck,"\r\n",2) > 0)
daniele 2:540f6e142d59 594 {
daniele 2:540f6e142d59 595 client->state = HTTP_WAIT_DATA;
daniele 2:540f6e142d59 596 //free the buffer
daniele 2:540f6e142d59 597 pico_free(client->buffer);
daniele 2:540f6e142d59 598 client->buffer = NULL;
daniele 2:540f6e142d59 599 server.wakeup(EV_HTTP_SENT,client->connectionID);
daniele 2:540f6e142d59 600 }
daniele 2:540f6e142d59 601 }
daniele 2:540f6e142d59 602
daniele 2:540f6e142d59 603 }
daniele 2:540f6e142d59 604
daniele 2:540f6e142d59 605 int readData(struct httpClient * client)
daniele 2:540f6e142d59 606 {
daniele 2:540f6e142d59 607 if(client->state == HTTP_WAIT_HDR)
daniele 2:540f6e142d59 608 {
daniele 2:540f6e142d59 609 if(parseRequest(client)<0 || readRemainingHeader(client)<0)
daniele 2:540f6e142d59 610 {
daniele 2:540f6e142d59 611 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 612 }
daniele 2:540f6e142d59 613 } // continue with this in case the header comes line by line not a big chunk
daniele 2:540f6e142d59 614 else if(client->state == HTTP_WAIT_EOF_HDR)
daniele 2:540f6e142d59 615 {
daniele 2:540f6e142d59 616 if(readRemainingHeader(client)<0 )
daniele 2:540f6e142d59 617 return HTTP_RETURN_ERROR;
daniele 2:540f6e142d59 618 }
daniele 2:540f6e142d59 619
daniele 2:540f6e142d59 620 if(client->state == HTTP_EOF_HDR)
daniele 2:540f6e142d59 621 {
daniele 2:540f6e142d59 622 client->state = HTTP_WAIT_RESPONSE;
daniele 2:540f6e142d59 623 pico_socket_shutdown(client->sck,PICO_SHUT_RD);
daniele 2:540f6e142d59 624 server.wakeup(EV_HTTP_REQ,client->connectionID);
daniele 2:540f6e142d59 625 }
daniele 2:540f6e142d59 626
daniele 2:540f6e142d59 627 return HTTP_RETURN_OK;
daniele 2:540f6e142d59 628 }
daniele 2:540f6e142d59 629
daniele 2:540f6e142d59 630 struct httpClient * findClient(uint16_t conn)
daniele 2:540f6e142d59 631 {
daniele 2:540f6e142d59 632 struct httpClient dummy = {.connectionID = conn};
daniele 2:540f6e142d59 633
daniele 2:540f6e142d59 634 return pico_tree_findKey(&pico_http_clients,&dummy);
daniele 2:540f6e142d59 635 }
daniele 2:540f6e142d59 636 #endif