httpclient.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. /*
  2. * ----------------------------------------------------------------------------
  3. * "THE BEER-WARE LICENSE" (Revision 42):
  4. * Martin d'Allens <martin.dallens@gmail.com> wrote this file. As long as you retain
  5. * this notice you can do whatever you want with this stuff. If we meet some day,
  6. * and you think this stuff is worth it, you can buy me a beer in return.
  7. * ----------------------------------------------------------------------------
  8. */
  9. /*
  10. * FIXME: sprintf->snprintf everywhere.
  11. * FIXME: support null characters in responses.
  12. */
  13. #include "osapi.h"
  14. #include "user_interface.h"
  15. #include "espconn.h"
  16. #include "mem.h"
  17. #include "limits.h"
  18. #include "httpclient.h"
  19. /* Internal state. */
  20. typedef struct request_args_t {
  21. char * hostname;
  22. int port;
  23. bool secure;
  24. char * method;
  25. char * path;
  26. char * headers;
  27. char * post_data;
  28. char * buffer;
  29. int buffer_size;
  30. int timeout;
  31. os_timer_t timeout_timer;
  32. http_callback_t callback_handle;
  33. } request_args_t;
  34. static char * ICACHE_FLASH_ATTR esp_strdup( const char * str )
  35. {
  36. if ( str == NULL )
  37. {
  38. return(NULL);
  39. }
  40. char * new_str = (char *) os_malloc( os_strlen( str ) + 1 ); /* 1 for null character */
  41. if ( new_str == NULL )
  42. {
  43. HTTPCLIENT_DEBUG( "esp_strdup: malloc error" );
  44. return(NULL);
  45. }
  46. os_strcpy( new_str, str );
  47. return(new_str);
  48. }
  49. static int ICACHE_FLASH_ATTR
  50. esp_isupper( char c )
  51. {
  52. return(c >= 'A' && c <= 'Z');
  53. }
  54. static int ICACHE_FLASH_ATTR
  55. esp_isalpha( char c )
  56. {
  57. return( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') );
  58. }
  59. static int ICACHE_FLASH_ATTR
  60. esp_isspace( char c )
  61. {
  62. return(c == ' ' || c == '\t' || c == '\n' || c == '\12');
  63. }
  64. static int ICACHE_FLASH_ATTR
  65. esp_isdigit( char c )
  66. {
  67. return(c >= '0' && c <= '9');
  68. }
  69. /*
  70. * Convert a string to a long integer.
  71. *
  72. * Ignores `locale' stuff. Assumes that the upper and lower case
  73. * alphabets and digits are each contiguous.
  74. */
  75. long ICACHE_FLASH_ATTR
  76. esp_strtol( nptr, endptr, base )
  77. const char *nptr;
  78. char **endptr;
  79. int base;
  80. {
  81. const char *s = nptr;
  82. unsigned long acc;
  83. int c;
  84. unsigned long cutoff;
  85. int neg = 0, any, cutlim;
  86. /*
  87. * Skip white space and pick up leading +/- sign if any.
  88. * If base is 0, allow 0x for hex and 0 for octal, else
  89. * assume decimal; if base is already 16, allow 0x.
  90. */
  91. do
  92. {
  93. c = *s++;
  94. }
  95. while ( esp_isspace( c ) );
  96. if ( c == '-' )
  97. {
  98. neg = 1;
  99. c = *s++;
  100. } else if ( c == '+' )
  101. c = *s++;
  102. if ( (base == 0 || base == 16) &&
  103. c == '0' && (*s == 'x' || *s == 'X') )
  104. {
  105. c = s[1];
  106. s += 2;
  107. base = 16;
  108. } else if ( (base == 0 || base == 2) &&
  109. c == '0' && (*s == 'b' || *s == 'B') )
  110. {
  111. c = s[1];
  112. s += 2;
  113. base = 2;
  114. }
  115. if ( base == 0 )
  116. base = c == '0' ? 8 : 10;
  117. /*
  118. * Compute the cutoff value between legal numbers and illegal
  119. * numbers. That is the largest legal value, divided by the
  120. * base. An input number that is greater than this value, if
  121. * followed by a legal input character, is too big. One that
  122. * is equal to this value may be valid or not; the limit
  123. * between valid and invalid numbers is then based on the last
  124. * digit. For instance, if the range for longs is
  125. * [-2147483648..2147483647] and the input base is 10,
  126. * cutoff will be set to 214748364 and cutlim to either
  127. * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
  128. * a value > 214748364, or equal but the next digit is > 7 (or 8),
  129. * the number is too big, and we will return a range error.
  130. *
  131. * Set any if any `digits' consumed; make it negative to indicate
  132. * overflow.
  133. */
  134. cutoff = neg ? -(unsigned long) LONG_MIN : LONG_MAX;
  135. cutlim = cutoff % (unsigned long) base;
  136. cutoff /= (unsigned long) base;
  137. for ( acc = 0, any = 0;; c = *s++ )
  138. {
  139. if ( esp_isdigit( c ) )
  140. c -= '0';
  141. else if ( esp_isalpha( c ) )
  142. c -= esp_isupper( c ) ? 'A' - 10 : 'a' - 10;
  143. else
  144. break;
  145. if ( c >= base )
  146. break;
  147. if ( any < 0 || acc > cutoff || acc == cutoff && c > cutlim )
  148. any = -1;
  149. else
  150. {
  151. any = 1;
  152. acc *= base;
  153. acc += c;
  154. }
  155. }
  156. if ( any < 0 )
  157. {
  158. acc = neg ? LONG_MIN : LONG_MAX;
  159. /* errno = ERANGE; */
  160. } else if ( neg )
  161. acc = -acc;
  162. if ( endptr != 0 )
  163. *endptr = (char *) (any ? s - 1 : nptr);
  164. return(acc);
  165. }
  166. static int ICACHE_FLASH_ATTR http_chunked_decode( const char * chunked, char * decode )
  167. {
  168. int i = 0, j = 0;
  169. int decode_size = 0;
  170. char *str = (char *) chunked;
  171. do
  172. {
  173. char * endstr = NULL;
  174. /* [chunk-size] */
  175. i = esp_strtol( str + j, endstr, 16 );
  176. HTTPCLIENT_DEBUG( "Chunk Size:%d\r\n", i );
  177. if ( i <= 0 )
  178. break;
  179. /* [chunk-size-end-ptr] */
  180. endstr = (char *) os_strstr( str + j, "\r\n" );
  181. /* [chunk-ext] */
  182. j += endstr - (str + j);
  183. /* [CRLF] */
  184. j += 2;
  185. /* [chunk-data] */
  186. decode_size += i;
  187. os_memcpy( (char *) &decode[decode_size - i], (char *) str + j, i );
  188. j += i;
  189. /* [CRLF] */
  190. j += 2;
  191. }
  192. while ( true );
  193. /*
  194. *
  195. * footer CRLF
  196. *
  197. */
  198. return(j);
  199. }
  200. static void ICACHE_FLASH_ATTR http_receive_callback( void * arg, char * buf, unsigned short len )
  201. {
  202. struct espconn * conn = (struct espconn *) arg;
  203. request_args_t * req = (request_args_t *) conn->reverse;
  204. if ( req->buffer == NULL )
  205. {
  206. return;
  207. }
  208. /* Let's do the equivalent of a realloc(). */
  209. const int new_size = req->buffer_size + len;
  210. char * new_buffer;
  211. if ( new_size > BUFFER_SIZE_MAX || NULL == (new_buffer = (char *) os_malloc( new_size ) ) )
  212. {
  213. HTTPCLIENT_DEBUG( "Response too long (%d)\n", new_size );
  214. req->buffer[0] = '\0'; /* Discard the buffer to avoid using an incomplete response. */
  215. if ( req->secure )
  216. espconn_secure_disconnect( conn );
  217. else
  218. espconn_disconnect( conn );
  219. return; /* The disconnect callback will be called. */
  220. }
  221. os_memcpy( new_buffer, req->buffer, req->buffer_size );
  222. os_memcpy( new_buffer + req->buffer_size - 1 /*overwrite the null character*/, buf, len ); /* Append new data. */
  223. new_buffer[new_size - 1] = '\0'; /* Make sure there is an end of string. */
  224. os_free( req->buffer );
  225. req->buffer = new_buffer;
  226. req->buffer_size = new_size;
  227. }
  228. static void ICACHE_FLASH_ATTR http_send_callback( void * arg )
  229. {
  230. struct espconn * conn = (struct espconn *) arg;
  231. request_args_t * req = (request_args_t *) conn->reverse;
  232. if ( req->post_data == NULL )
  233. {
  234. HTTPCLIENT_DEBUG( "All sent\n" );
  235. }
  236. else
  237. {
  238. /* The headers were sent, now send the contents. */
  239. HTTPCLIENT_DEBUG( "Sending request body\n" );
  240. if ( req->secure )
  241. espconn_secure_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
  242. else
  243. espconn_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
  244. os_free( req->post_data );
  245. req->post_data = NULL;
  246. }
  247. }
  248. static void ICACHE_FLASH_ATTR http_connect_callback( void * arg )
  249. {
  250. HTTPCLIENT_DEBUG( "Connected\n" );
  251. struct espconn * conn = (struct espconn *) arg;
  252. request_args_t * req = (request_args_t *) conn->reverse;
  253. espconn_regist_recvcb( conn, http_receive_callback );
  254. espconn_regist_sentcb( conn, http_send_callback );
  255. char post_headers[32] = "";
  256. if ( req->post_data != NULL ) /* If there is data then add Content-Length header. */
  257. {
  258. os_sprintf( post_headers, "Content-Length: %d\r\n", strlen( req->post_data ) );
  259. }
  260. if(req->headers == NULL) /* Avoid NULL pointer, it may cause exception */
  261. {
  262. req->headers = (char *)os_malloc(sizeof(char));
  263. req->headers[0] = '\0';
  264. }
  265. char buf[69 + strlen( req->method ) + strlen( req->path ) + strlen( req->hostname ) +
  266. strlen( req->headers ) + strlen( post_headers )];
  267. int len = os_sprintf( buf,
  268. "%s %s HTTP/1.1\r\n"
  269. "Host: %s:%d\r\n"
  270. "Connection: close\r\n"
  271. "User-Agent: ESP8266\r\n"
  272. "%s"
  273. "%s"
  274. "\r\n",
  275. req->method, req->path, req->hostname, req->port, req->headers, post_headers );
  276. if ( req->secure )
  277. espconn_secure_send( conn, (uint8_t *) buf, len );
  278. else
  279. espconn_send( conn, (uint8_t *) buf, len );
  280. if(req->headers != NULL)
  281. os_free( req->headers );
  282. req->headers = NULL;
  283. HTTPCLIENT_DEBUG( "Sending request header\n" );
  284. }
  285. static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
  286. {
  287. HTTPCLIENT_DEBUG( "Disconnected\n" );
  288. struct espconn *conn = (struct espconn *) arg;
  289. if ( conn == NULL )
  290. {
  291. return;
  292. }
  293. if ( conn->proto.tcp != NULL )
  294. {
  295. os_free( conn->proto.tcp );
  296. }
  297. if ( conn->reverse != NULL )
  298. {
  299. request_args_t * req = (request_args_t *) conn->reverse;
  300. int http_status = -1;
  301. char * body = "";
  302. // Turn off timeout timer
  303. os_timer_disarm( &(req->timeout_timer) );
  304. if ( req->buffer == NULL )
  305. {
  306. HTTPCLIENT_DEBUG( "Buffer shouldn't be NULL\n" );
  307. }
  308. else if ( req->buffer[0] != '\0' )
  309. {
  310. /* FIXME: make sure this is not a partial response, using the Content-Length header. */
  311. const char * version = "HTTP/1.1 ";
  312. if ( os_strncmp( req->buffer, version, strlen( version ) ) != 0 )
  313. {
  314. HTTPCLIENT_DEBUG( "Invalid version in %s\n", req->buffer );
  315. }
  316. else
  317. {
  318. http_status = atoi( req->buffer + strlen( version ) );
  319. body = (char *) os_strstr( req->buffer, "\r\n\r\n" ) + 4;
  320. if ( os_strstr( req->buffer, "Transfer-Encoding: chunked" ) )
  321. {
  322. int body_size = req->buffer_size - (body - req->buffer);
  323. char chunked_decode_buffer[body_size];
  324. os_memset( chunked_decode_buffer, 0, body_size );
  325. /* Chuncked data */
  326. http_chunked_decode( body, chunked_decode_buffer );
  327. os_memcpy( body, chunked_decode_buffer, body_size );
  328. }
  329. }
  330. }
  331. if ( req->callback_handle != NULL ) /* Callback is optional. */
  332. {
  333. req->callback_handle( body, http_status, req->buffer );
  334. }
  335. os_free( req->buffer );
  336. os_free( req->hostname );
  337. os_free( req->method );
  338. os_free( req->path );
  339. os_free( req );
  340. }
  341. /* Fix memory leak. */
  342. espconn_delete( conn );
  343. os_free( conn );
  344. }
  345. static void ICACHE_FLASH_ATTR http_error_callback( void *arg, sint8 errType )
  346. {
  347. HTTPCLIENT_DEBUG( "Disconnected with error\n" );
  348. http_disconnect_callback( arg );
  349. }
  350. static void ICACHE_FLASH_ATTR http_timeout_callback( void *arg )
  351. {
  352. HTTPCLIENT_DEBUG( "Connection timeout\n" );
  353. struct espconn * conn = (struct espconn *) arg;
  354. if ( conn == NULL )
  355. {
  356. return;
  357. }
  358. if ( conn->reverse == NULL )
  359. {
  360. return;
  361. }
  362. request_args_t * req = (request_args_t *) conn->reverse;
  363. /* Call disconnect */
  364. if ( req->secure )
  365. espconn_secure_disconnect( conn );
  366. else
  367. espconn_disconnect( conn );
  368. }
  369. static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_t * addr, void * arg )
  370. {
  371. request_args_t * req = (request_args_t *) arg;
  372. if ( addr == NULL )
  373. {
  374. HTTPCLIENT_DEBUG( "DNS failed for %s\n", hostname );
  375. if ( req->callback_handle != NULL )
  376. {
  377. req->callback_handle( "", -1, "" );
  378. }
  379. os_free( req );
  380. }
  381. else
  382. {
  383. HTTPCLIENT_DEBUG( "DNS found %s " IPSTR "\n", hostname, IP2STR( addr ) );
  384. struct espconn * conn = (struct espconn *) os_malloc( sizeof(struct espconn) );
  385. conn->type = ESPCONN_TCP;
  386. conn->state = ESPCONN_NONE;
  387. conn->proto.tcp = (esp_tcp *) os_malloc( sizeof(esp_tcp) );
  388. conn->proto.tcp->local_port = espconn_port();
  389. conn->proto.tcp->remote_port = req->port;
  390. conn->reverse = req;
  391. os_memcpy( conn->proto.tcp->remote_ip, addr, 4 );
  392. espconn_regist_connectcb( conn, http_connect_callback );
  393. espconn_regist_disconcb( conn, http_disconnect_callback );
  394. espconn_regist_reconcb( conn, http_error_callback );
  395. /* Set connection timeout timer */
  396. os_timer_disarm( &(req->timeout_timer) );
  397. os_timer_setfn( &(req->timeout_timer), (os_timer_func_t *) http_timeout_callback, conn );
  398. os_timer_arm( &(req->timeout_timer), req->timeout, false );
  399. if ( req->secure )
  400. {
  401. espconn_secure_set_size( ESPCONN_CLIENT, 5120 ); /* set SSL buffer size */
  402. espconn_secure_connect( conn );
  403. }
  404. else
  405. {
  406. espconn_connect( conn );
  407. }
  408. }
  409. }
  410. void ICACHE_FLASH_ATTR http_raw_request( const char * hostname, int port, bool secure, const char * method, const char * path, const char * headers, const char * post_data, http_callback_t callback_handle )
  411. {
  412. HTTPCLIENT_DEBUG( "DNS request\n" );
  413. request_args_t * req = (request_args_t *) os_malloc( sizeof(request_args_t) );
  414. req->hostname = esp_strdup( hostname );
  415. req->port = port;
  416. req->secure = secure;
  417. req->method = esp_strdup( method );
  418. req->path = esp_strdup( path );
  419. req->headers = esp_strdup( headers );
  420. req->post_data = esp_strdup( post_data );
  421. req->buffer_size = 1;
  422. req->buffer = (char *) os_malloc( 1 );
  423. req->buffer[0] = '\0'; /* Empty string. */
  424. req->callback_handle = callback_handle;
  425. req->timeout = HTTP_REQUEST_TIMEOUT_MS;
  426. ip_addr_t addr;
  427. err_t error = espconn_gethostbyname( (struct espconn *) req, /* It seems we don't need a real espconn pointer here. */
  428. hostname, &addr, http_dns_callback );
  429. if ( error == ESPCONN_INPROGRESS )
  430. {
  431. HTTPCLIENT_DEBUG( "DNS pending\n" );
  432. }
  433. else if ( error == ESPCONN_OK )
  434. {
  435. /* Already in the local names table (or hostname was an IP address), execute the callback ourselves. */
  436. http_dns_callback( hostname, &addr, req );
  437. }
  438. else
  439. {
  440. if ( error == ESPCONN_ARG )
  441. {
  442. HTTPCLIENT_DEBUG( "DNS arg error %s\n", hostname );
  443. }else {
  444. HTTPCLIENT_DEBUG( "DNS error code %d\n", error );
  445. }
  446. http_dns_callback( hostname, NULL, req ); /* Handle all DNS errors the same way. */
  447. }
  448. }
  449. /*
  450. * Parse an URL of the form http://host:port/path
  451. * <host> can be a hostname or an IP address
  452. * <port> is optional
  453. */
  454. void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, const char * headers, const char * post_data, http_callback_t callback_handle )
  455. {
  456. /*
  457. * FIXME: handle HTTP auth with http://user:pass@host/
  458. * FIXME: get rid of the #anchor part if present.
  459. */
  460. char hostname[128] = "";
  461. int port = 80;
  462. bool secure = false;
  463. bool is_http = os_strncmp( url, "http://", strlen( "http://" ) ) == 0;
  464. bool is_https = os_strncmp( url, "https://", strlen( "https://" ) ) == 0;
  465. if ( is_http )
  466. url += strlen( "http://" ); /* Get rid of the protocol. */
  467. else if ( is_https )
  468. {
  469. port = 443;
  470. secure = true;
  471. url += strlen( "https://" ); /* Get rid of the protocol. */
  472. }
  473. else
  474. {
  475. HTTPCLIENT_DEBUG( "URL is not HTTP or HTTPS %s\n", url );
  476. return;
  477. }
  478. char * path = os_strchr( url, '/' );
  479. if ( path == NULL )
  480. {
  481. path = os_strchr( url, '\0' ); /* Pointer to end of string. */
  482. }
  483. char * colon = os_strchr( url, ':' );
  484. if ( colon > path )
  485. {
  486. colon = NULL; /* Limit the search to characters before the path. */
  487. }
  488. if ( colon == NULL ) /* The port is not present. */
  489. {
  490. os_memcpy( hostname, url, path - url );
  491. hostname[path - url] = '\0';
  492. }
  493. else
  494. {
  495. port = atoi( colon + 1 );
  496. if ( port == 0 )
  497. {
  498. HTTPCLIENT_DEBUG( "Port error %s\n", url );
  499. return;
  500. }
  501. os_memcpy( hostname, url, colon - url );
  502. hostname[colon - url] = '\0';
  503. }
  504. if ( path[0] == '\0' ) /* Empty path is not allowed. */
  505. {
  506. path = "/";
  507. }
  508. HTTPCLIENT_DEBUG( "hostname=%s\n", hostname );
  509. HTTPCLIENT_DEBUG( "port=%d\n", port );
  510. HTTPCLIENT_DEBUG( "method=%s\n", method );
  511. HTTPCLIENT_DEBUG( "path=%s\n", path );
  512. http_raw_request( hostname, port, secure, method, path, headers, post_data, callback_handle );
  513. }
  514. /*
  515. * Parse an URL of the form http://host:port/path
  516. * <host> can be a hostname or an IP address
  517. * <port> is optional
  518. */
  519. void ICACHE_FLASH_ATTR http_post( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
  520. {
  521. http_request( url, "POST", headers, post_data, callback_handle );
  522. }
  523. void ICACHE_FLASH_ATTR http_get( const char * url, const char * headers, http_callback_t callback_handle )
  524. {
  525. http_request( url, "GET", headers, NULL, callback_handle );
  526. }
  527. void ICACHE_FLASH_ATTR http_delete( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
  528. {
  529. http_request( url, "DELETE", headers, post_data, callback_handle );
  530. }
  531. void ICACHE_FLASH_ATTR http_put( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
  532. {
  533. http_request( url, "PUT", headers, post_data, callback_handle );
  534. }
  535. void ICACHE_FLASH_ATTR http_callback_example( char * response, int http_status, char * full_response )
  536. {
  537. os_printf( "http_status=%d\n", http_status );
  538. if ( http_status != HTTP_STATUS_GENERIC_ERROR )
  539. {
  540. os_printf( "strlen(full_response)=%d\n", strlen( full_response ) );
  541. os_printf( "response=%s<EOF>\n", response );
  542. }
  543. }