httpclient.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  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 <stdio.h>
  15. #include <stdlib.h>
  16. #include <limits.h>
  17. #include "user_interface.h"
  18. #include "espconn.h"
  19. #include "mem.h"
  20. #include "httpclient.h"
  21. #include "pm/swtimer.h"
  22. #define REDIRECTION_FOLLOW_MAX 20
  23. /* Internal state. */
  24. typedef struct request_args_t {
  25. char * hostname;
  26. int port;
  27. #ifdef CLIENT_SSL_ENABLE
  28. bool secure;
  29. #endif
  30. char * method;
  31. char * path;
  32. char * headers;
  33. char * post_data;
  34. char * buffer;
  35. int buffer_size;
  36. int redirect_follow_count;
  37. int timeout;
  38. os_timer_t timeout_timer;
  39. http_callback_t callback_handle;
  40. } request_args_t;
  41. static char * ICACHE_FLASH_ATTR esp_strdup( const char * str )
  42. {
  43. if ( str == NULL )
  44. {
  45. return(NULL);
  46. }
  47. char * new_str = (char *) os_malloc( os_strlen( str ) + 1 ); /* 1 for null character */
  48. if ( new_str == NULL )
  49. {
  50. HTTPCLIENT_DEBUG( "esp_strdup: malloc error" );
  51. return(NULL);
  52. }
  53. os_strcpy( new_str, str );
  54. return(new_str);
  55. }
  56. static int ICACHE_FLASH_ATTR
  57. esp_isupper( char c )
  58. {
  59. return(c >= 'A' && c <= 'Z');
  60. }
  61. static int ICACHE_FLASH_ATTR
  62. esp_isalpha( char c )
  63. {
  64. return( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') );
  65. }
  66. static int ICACHE_FLASH_ATTR
  67. esp_isspace( char c )
  68. {
  69. return(c == ' ' || c == '\t' || c == '\n' || c == '\12');
  70. }
  71. static int ICACHE_FLASH_ATTR
  72. esp_isdigit( char c )
  73. {
  74. return(c >= '0' && c <= '9');
  75. }
  76. static int ICACHE_FLASH_ATTR http_chunked_decode( const char * chunked, char * decode )
  77. {
  78. int i = 0, j = 0;
  79. int decode_size = 0;
  80. char *str = (char *) chunked;
  81. do
  82. {
  83. char * endstr;
  84. /* [chunk-size] */
  85. i = strtoul( str + j, NULL, 16 );
  86. HTTPCLIENT_DEBUG( "Chunk Size:%d", i );
  87. if ( i <= 0 )
  88. break;
  89. /* [chunk-size-end-ptr] */
  90. endstr = (char *) os_strstr( str + j, "\r\n" );
  91. /* [chunk-ext] */
  92. j += endstr - (str + j);
  93. /* [CRLF] */
  94. j += 2;
  95. /* [chunk-data] */
  96. decode_size += i;
  97. os_memcpy( (char *) &decode[decode_size - i], (char *) str + j, i );
  98. j += i;
  99. /* [CRLF] */
  100. j += 2;
  101. }
  102. while ( true );
  103. /*
  104. *
  105. * footer CRLF
  106. *
  107. */
  108. return(decode_size);
  109. }
  110. static void ICACHE_FLASH_ATTR http_receive_callback( void * arg, char * buf, unsigned short len )
  111. {
  112. struct espconn * conn = (struct espconn *) arg;
  113. request_args_t * req = (request_args_t *) conn->reverse;
  114. if ( req->buffer == NULL )
  115. {
  116. return;
  117. }
  118. /* Let's do the equivalent of a realloc(). */
  119. const int new_size = req->buffer_size + len;
  120. char * new_buffer;
  121. if ( new_size > BUFFER_SIZE_MAX || NULL == (new_buffer = (char *) os_malloc( new_size ) ) )
  122. {
  123. HTTPCLIENT_ERR( "Response too long (%d)", new_size );
  124. req->buffer[0] = '\0'; /* Discard the buffer to avoid using an incomplete response. */
  125. #ifdef CLIENT_SSL_ENABLE
  126. if ( req->secure )
  127. espconn_secure_disconnect( conn );
  128. else
  129. #endif
  130. espconn_disconnect( conn );
  131. return; /* The disconnect callback will be called. */
  132. }
  133. os_memcpy( new_buffer, req->buffer, req->buffer_size );
  134. os_memcpy( new_buffer + req->buffer_size - 1 /*overwrite the null character*/, buf, len ); /* Append new data. */
  135. new_buffer[new_size - 1] = '\0'; /* Make sure there is an end of string. */
  136. os_free( req->buffer );
  137. req->buffer = new_buffer;
  138. req->buffer_size = new_size;
  139. }
  140. static void ICACHE_FLASH_ATTR http_send_callback( void * arg )
  141. {
  142. struct espconn * conn = (struct espconn *) arg;
  143. request_args_t * req = (request_args_t *) conn->reverse;
  144. if ( req->post_data == NULL )
  145. {
  146. HTTPCLIENT_DEBUG( "All sent" );
  147. }
  148. else
  149. {
  150. /* The headers were sent, now send the contents. */
  151. HTTPCLIENT_DEBUG( "Sending request body" );
  152. #ifdef CLIENT_SSL_ENABLE
  153. if ( req->secure )
  154. espconn_secure_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
  155. else
  156. #endif
  157. espconn_send( conn, (uint8_t *) req->post_data, strlen( req->post_data ) );
  158. os_free( req->post_data );
  159. req->post_data = NULL;
  160. }
  161. }
  162. static void ICACHE_FLASH_ATTR http_connect_callback( void * arg )
  163. {
  164. HTTPCLIENT_DEBUG( "Connected" );
  165. struct espconn * conn = (struct espconn *) arg;
  166. request_args_t * req = (request_args_t *) conn->reverse;
  167. espconn_regist_recvcb( conn, http_receive_callback );
  168. espconn_regist_sentcb( conn, http_send_callback );
  169. char post_headers[32] = "";
  170. if ( req->post_data != NULL ) /* If there is data then add Content-Length header. */
  171. {
  172. os_sprintf( post_headers, "Content-Length: %d\r\n", strlen( req->post_data ) );
  173. }
  174. if(req->headers == NULL) /* Avoid NULL pointer, it may cause exception */
  175. {
  176. req->headers = (char *)os_malloc(sizeof(char));
  177. req->headers[0] = '\0';
  178. }
  179. char ua_header[32] = "";
  180. int ua_len = 0;
  181. if (strcasestr( req->headers, "User-Agent:" ) == NULL )
  182. {
  183. os_sprintf( ua_header, "User-Agent: %s\r\n", "ESP8266" );
  184. ua_len = strlen(ua_header);
  185. }
  186. char * host_header = "";
  187. int host_len = 0;
  188. if ( strcasestr( req->headers, "Host:" ) == NULL )
  189. {
  190. int max_header_len = 9 + strlen(req->hostname); // 9 is fixed size of "Host:[space][cr][lf]\0"
  191. if ((req->port == 80)
  192. #ifdef CLIENT_SSL_ENABLE
  193. || ((req->port == 443) && ( req->secure ))
  194. #endif
  195. )
  196. {
  197. host_header = alloca(max_header_len);
  198. os_sprintf( host_header, "Host: %s\r\n", req->hostname );
  199. }
  200. else
  201. {
  202. host_header = alloca(max_header_len + 6); // 6 is worst case of ":port" where port is maximum 5 digits
  203. os_sprintf( host_header, "Host: %s:%d\r\n", req->hostname, req->port );
  204. }
  205. host_len = strlen(host_header);
  206. }
  207. char buf[69 + strlen( req->method ) + strlen( req->path ) + host_len +
  208. strlen( req->headers ) + ua_len + strlen( post_headers )];
  209. int len = os_sprintf( buf,
  210. "%s %s HTTP/1.1\r\n"
  211. "%s" // Host (if not provided in the headers from Lua)
  212. "Connection: close\r\n"
  213. "%s" // Headers from Lua (optional)
  214. "%s" // User-Agent (if not provided in the headers from Lua)
  215. "%s" // Content-Length
  216. "\r\n",
  217. req->method, req->path, host_header, req->headers, ua_header, post_headers );
  218. #ifdef CLIENT_SSL_ENABLE
  219. if (req->secure)
  220. {
  221. espconn_secure_send( conn, (uint8_t *) buf, len );
  222. }
  223. else
  224. #endif
  225. {
  226. espconn_send( conn, (uint8_t *) buf, len );
  227. }
  228. if (req->headers != NULL)
  229. {
  230. os_free( req->headers );
  231. }
  232. req->headers = NULL;
  233. HTTPCLIENT_DEBUG( "Sending request header" );
  234. }
  235. static void http_free_req( request_args_t * req)
  236. {
  237. if (req->buffer) {
  238. os_free( req->buffer );
  239. }
  240. if (req->post_data) {
  241. os_free( req->post_data );
  242. }
  243. if (req->headers) {
  244. os_free( req->headers );
  245. }
  246. os_free( req->hostname );
  247. os_free( req->method );
  248. os_free( req->path );
  249. os_free( req );
  250. }
  251. static void ICACHE_FLASH_ATTR http_disconnect_callback( void * arg )
  252. {
  253. HTTPCLIENT_DEBUG( "Disconnected" );
  254. struct espconn *conn = (struct espconn *) arg;
  255. if ( conn == NULL )
  256. {
  257. return;
  258. }
  259. if ( conn->proto.tcp != NULL )
  260. {
  261. os_free( conn->proto.tcp );
  262. }
  263. if ( conn->reverse != NULL )
  264. {
  265. request_args_t * req = (request_args_t *) conn->reverse;
  266. int http_status = -1;
  267. char * body = "";
  268. int body_size = 0;
  269. // Turn off timeout timer
  270. os_timer_disarm( &(req->timeout_timer) );
  271. if ( req->buffer == NULL )
  272. {
  273. HTTPCLIENT_DEBUG( "Buffer probably shouldn't be NULL" );
  274. }
  275. else if ( req->buffer[0] != '\0' )
  276. {
  277. /* FIXME: make sure this is not a partial response, using the Content-Length header. */
  278. const char * version_1_0 = "HTTP/1.0 ";
  279. const char * version_1_1 = "HTTP/1.1 ";
  280. if (( os_strncmp( req->buffer, version_1_0, strlen( version_1_0 ) ) != 0 ) &&
  281. ( os_strncmp( req->buffer, version_1_1, strlen( version_1_1 ) ) != 0 ))
  282. {
  283. HTTPCLIENT_ERR( "Invalid version in %s", req->buffer );
  284. }
  285. else
  286. {
  287. http_status = atoi( req->buffer + strlen( version_1_0 ) );
  288. char *locationOffset = (char *) strcasestr( req->buffer, "Location:" );
  289. if ( locationOffset != NULL && http_status >= 300 && http_status <= 308 ) {
  290. if (req->redirect_follow_count < REDIRECTION_FOLLOW_MAX) {
  291. locationOffset += strlen("location:");
  292. while (*locationOffset == ' ') { // skip url leading white-space
  293. locationOffset++;
  294. }
  295. char *locationOffsetEnd = (char *) os_strstr(locationOffset, "\r\n");
  296. if ( locationOffsetEnd == NULL ) {
  297. HTTPCLIENT_ERR( "Found Location header but was incomplete" );
  298. http_status = -1;
  299. } else {
  300. *locationOffsetEnd = '\0';
  301. req->redirect_follow_count++;
  302. // Check if url is absolute
  303. bool url_has_protocol =
  304. os_strncmp( locationOffset, "http://", strlen( "http://" ) ) == 0 ||
  305. os_strncmp( locationOffset, "https://", strlen( "https://" ) ) == 0;
  306. if ( url_has_protocol ) {
  307. http_request( locationOffset, req->method, req->headers,
  308. req->post_data, req->callback_handle, req->redirect_follow_count );
  309. } else {
  310. if ( os_strncmp( locationOffset, "/", 1 ) == 0) { // relative and full path
  311. http_raw_request( req->hostname, req->port,
  312. #ifdef CLIENT_SSL_ENABLE
  313. req->secure,
  314. #else
  315. 0,
  316. #endif
  317. req->method, locationOffset, req->headers, req->post_data, req->callback_handle, req->redirect_follow_count );
  318. } else { // relative and relative path
  319. // find last /
  320. const char *pathFolderEnd = strrchr(req->path, '/');
  321. int pathFolderLength = pathFolderEnd - req->path;
  322. pathFolderLength++; // use the '/'
  323. int locationLength = strlen(locationOffset);
  324. locationLength++; // use the '\0'
  325. // append pathFolder with given relative path
  326. char *completeRelativePath = (char *) os_malloc(pathFolderLength + locationLength);
  327. os_memcpy( completeRelativePath, req->path, pathFolderLength );
  328. os_memcpy( completeRelativePath + pathFolderLength, locationOffset, locationLength);
  329. http_raw_request( req->hostname, req->port,
  330. #ifdef CLIENT_SSL_ENABLE
  331. req->secure,
  332. #else
  333. 0,
  334. #endif
  335. req->method, completeRelativePath, req->headers, req->post_data, req->callback_handle, req->redirect_follow_count );
  336. os_free( completeRelativePath );
  337. }
  338. }
  339. http_free_req( req );
  340. espconn_delete( conn );
  341. os_free( conn );
  342. return;
  343. }
  344. } else {
  345. HTTPCLIENT_ERR("Too many redirections");
  346. http_status = -1;
  347. }
  348. } else {
  349. body = (char *) os_strstr(req->buffer, "\r\n\r\n");
  350. if (NULL == body) {
  351. /* Find missing body */
  352. HTTPCLIENT_ERR("Body shouldn't be NULL");
  353. /* To avoid NULL body */
  354. body = "";
  355. } else {
  356. /* Skip CR & LF */
  357. body = body + 4;
  358. }
  359. body_size = req->buffer_size - (body - req->buffer);
  360. if ( strcasestr( req->buffer, "Transfer-Encoding: chunked" ) )
  361. {
  362. char *chunked_decode_buffer = os_malloc(body_size);
  363. os_memset( chunked_decode_buffer, 0, body_size );
  364. /* Chuncked data */
  365. body_size = http_chunked_decode( body, chunked_decode_buffer );
  366. os_memcpy( body, chunked_decode_buffer, body_size );
  367. os_free( chunked_decode_buffer );
  368. }
  369. else --body_size;
  370. }
  371. }
  372. }
  373. if ( req->callback_handle != NULL ) /* Callback is optional. */
  374. {
  375. char *req_buffer = req->buffer;
  376. req->buffer = NULL;
  377. http_callback_t req_callback;
  378. req_callback = req->callback_handle;
  379. http_free_req( req );
  380. req_callback( body, http_status, &req_buffer, body_size );
  381. if (req_buffer) {
  382. os_free(req_buffer);
  383. }
  384. } else {
  385. http_free_req( req );
  386. }
  387. }
  388. /* Fix memory leak. */
  389. espconn_delete( conn );
  390. os_free( conn );
  391. }
  392. static void ICACHE_FLASH_ATTR http_timeout_callback( void *arg )
  393. {
  394. HTTPCLIENT_ERR( "Connection timeout" );
  395. struct espconn * conn = (struct espconn *) arg;
  396. if ( conn == NULL )
  397. {
  398. HTTPCLIENT_DEBUG( "Connection is NULL" );
  399. return;
  400. }
  401. if ( conn->reverse == NULL )
  402. {
  403. HTTPCLIENT_DEBUG( "Connection request data (reverse) is NULL" );
  404. return;
  405. }
  406. request_args_t * req = (request_args_t *) conn->reverse;
  407. HTTPCLIENT_DEBUG( "Calling disconnect" );
  408. /* Call disconnect */
  409. sint8 result;
  410. #ifdef CLIENT_SSL_ENABLE
  411. if ( req->secure )
  412. result = espconn_secure_disconnect( conn );
  413. else
  414. #endif
  415. result = espconn_disconnect( conn );
  416. if (result == ESPCONN_OK || result == ESPCONN_INPROGRESS)
  417. return;
  418. else
  419. {
  420. /* not connected; execute the callback ourselves. */
  421. HTTPCLIENT_DEBUG( "manually Calling disconnect callback due to error %d", result );
  422. http_disconnect_callback( arg );
  423. }
  424. }
  425. static void ICACHE_FLASH_ATTR http_error_callback( void *arg, sint8 errType )
  426. {
  427. HTTPCLIENT_ERR( "Disconnected with error: %d", errType );
  428. http_timeout_callback( arg );
  429. }
  430. static void ICACHE_FLASH_ATTR http_dns_callback( const char * hostname, ip_addr_t * addr, void * arg )
  431. {
  432. request_args_t * req = (request_args_t *) arg;
  433. if ( addr == NULL )
  434. {
  435. HTTPCLIENT_ERR( "DNS failed for %s", hostname );
  436. if ( req->callback_handle != NULL )
  437. {
  438. req->callback_handle( "", -1, NULL, 0 );
  439. }
  440. http_free_req( req );
  441. }
  442. else
  443. {
  444. HTTPCLIENT_DEBUG( "DNS found %s " IPSTR, hostname, IP2STR( addr ) );
  445. struct espconn * conn = (struct espconn *) os_zalloc( sizeof(struct espconn) );
  446. conn->type = ESPCONN_TCP;
  447. conn->state = ESPCONN_NONE;
  448. conn->proto.tcp = (esp_tcp *) os_zalloc( sizeof(esp_tcp) );
  449. conn->proto.tcp->local_port = espconn_port();
  450. conn->proto.tcp->remote_port = req->port;
  451. conn->reverse = req;
  452. os_memcpy( conn->proto.tcp->remote_ip, addr, 4 );
  453. espconn_regist_connectcb( conn, http_connect_callback );
  454. espconn_regist_disconcb( conn, http_disconnect_callback );
  455. espconn_regist_reconcb( conn, http_error_callback );
  456. /* Set connection timeout timer */
  457. os_timer_disarm( &(req->timeout_timer) );
  458. os_timer_setfn( &(req->timeout_timer), (os_timer_func_t *) http_timeout_callback, conn );
  459. SWTIMER_REG_CB(http_timeout_callback, SWTIMER_IMMEDIATE);
  460. //http_timeout_callback frees memory used by this function and timer cannot be dropped
  461. os_timer_arm( &(req->timeout_timer), req->timeout, false );
  462. #ifdef CLIENT_SSL_ENABLE
  463. if ( req->secure )
  464. {
  465. espconn_secure_connect( conn );
  466. }
  467. else
  468. #endif
  469. {
  470. espconn_connect( conn );
  471. }
  472. }
  473. }
  474. 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, int redirect_follow_count )
  475. {
  476. HTTPCLIENT_DEBUG( "DNS request" );
  477. request_args_t * req = (request_args_t *) os_zalloc( sizeof(request_args_t) );
  478. req->hostname = esp_strdup( hostname );
  479. req->port = port;
  480. #ifdef CLIENT_SSL_ENABLE
  481. req->secure = secure;
  482. #endif
  483. req->method = esp_strdup( method );
  484. req->path = esp_strdup( path );
  485. req->headers = esp_strdup( headers );
  486. req->post_data = esp_strdup( post_data );
  487. req->buffer_size = 1;
  488. req->buffer = (char *) os_malloc( 1 );
  489. req->buffer[0] = '\0'; /* Empty string. */
  490. req->callback_handle = callback_handle;
  491. req->timeout = HTTP_REQUEST_TIMEOUT_MS;
  492. req->redirect_follow_count = redirect_follow_count;
  493. ip_addr_t addr;
  494. err_t error = dns_gethostbyname( hostname, &addr, http_dns_callback, req );
  495. if ( error == ERR_INPROGRESS )
  496. {
  497. HTTPCLIENT_DEBUG( "DNS pending" );
  498. }
  499. else if ( error == ERR_OK )
  500. {
  501. /* Already in the local names table (or hostname was an IP address), execute the callback ourselves. */
  502. http_dns_callback( hostname, &addr, req );
  503. }
  504. else
  505. {
  506. if ( error == ERR_ARG )
  507. {
  508. HTTPCLIENT_ERR( "DNS arg error %s", hostname );
  509. }else {
  510. HTTPCLIENT_ERR( "DNS error code %d", error );
  511. }
  512. http_dns_callback( hostname, NULL, req ); /* Handle all DNS errors the same way. */
  513. }
  514. }
  515. /*
  516. * Parse an URL of the form http://host:port/path
  517. * <host> can be a hostname or an IP address
  518. * <port> is optional
  519. */
  520. void ICACHE_FLASH_ATTR http_request( const char * url, const char * method, const char * headers, const char * post_data, http_callback_t callback_handle, int redirect_follow_count )
  521. {
  522. /*
  523. * FIXME: handle HTTP auth with http://user:pass@host/
  524. * FIXME: get rid of the #anchor part if present.
  525. */
  526. char hostname[128] = "";
  527. int port = 80;
  528. bool secure = false;
  529. bool is_http = os_strncmp( url, "http://", strlen( "http://" ) ) == 0;
  530. bool is_https = os_strncmp( url, "https://", strlen( "https://" ) ) == 0;
  531. if ( is_http )
  532. url += strlen( "http://" ); /* Get rid of the protocol. */
  533. else if ( is_https )
  534. {
  535. port = 443;
  536. secure = true;
  537. url += strlen( "https://" ); /* Get rid of the protocol. */
  538. }
  539. else
  540. {
  541. HTTPCLIENT_ERR( "URL is not HTTP or HTTPS %s", url );
  542. return;
  543. }
  544. char * path = os_strchr( url, '/' );
  545. if ( path == NULL )
  546. {
  547. path = os_strchr( url, '\0' ); /* Pointer to end of string. */
  548. }
  549. char * colon = os_strchr( url, ':' );
  550. if ( colon > path )
  551. {
  552. colon = NULL; /* Limit the search to characters before the path. */
  553. }
  554. if (path - url >= sizeof(hostname)) {
  555. HTTPCLIENT_ERR( "hostname is too long %s", url );
  556. return;
  557. }
  558. if ( colon == NULL ) /* The port is not present. */
  559. {
  560. os_memcpy( hostname, url, path - url );
  561. hostname[path - url] = '\0';
  562. }
  563. else
  564. {
  565. port = atoi( colon + 1 );
  566. if ( port == 0 )
  567. {
  568. HTTPCLIENT_ERR( "Port error %s", url );
  569. return;
  570. }
  571. os_memcpy( hostname, url, colon - url );
  572. hostname[colon - url] = '\0';
  573. }
  574. if ( path[0] == '\0' ) /* Empty path is not allowed. */
  575. {
  576. path = "/";
  577. }
  578. HTTPCLIENT_DEBUG( "hostname=%s", hostname );
  579. HTTPCLIENT_DEBUG( "port=%d", port );
  580. HTTPCLIENT_DEBUG( "method=%s", method );
  581. HTTPCLIENT_DEBUG( "path=%s", path );
  582. http_raw_request( hostname, port, secure, method, path, headers, post_data, callback_handle, redirect_follow_count);
  583. }
  584. /*
  585. * Parse an URL of the form http://host:port/path
  586. * <host> can be a hostname or an IP address
  587. * <port> is optional
  588. */
  589. void ICACHE_FLASH_ATTR http_post( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
  590. {
  591. http_request( url, "POST", headers, post_data, callback_handle, 0 );
  592. }
  593. void ICACHE_FLASH_ATTR http_get( const char * url, const char * headers, http_callback_t callback_handle )
  594. {
  595. http_request( url, "GET", headers, NULL, callback_handle, 0 );
  596. }
  597. void ICACHE_FLASH_ATTR http_delete( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
  598. {
  599. http_request( url, "DELETE", headers, post_data, callback_handle, 0 );
  600. }
  601. void ICACHE_FLASH_ATTR http_put( const char * url, const char * headers, const char * post_data, http_callback_t callback_handle )
  602. {
  603. http_request( url, "PUT", headers, post_data, callback_handle, 0 );
  604. }
  605. void ICACHE_FLASH_ATTR http_callback_example( char * response, int http_status, char * full_response )
  606. {
  607. dbg_printf( "http_status=%d\n", http_status );
  608. if ( http_status != HTTP_STATUS_GENERIC_ERROR )
  609. {
  610. dbg_printf( "strlen(full_response)=%d\n", strlen( full_response ) );
  611. dbg_printf( "response=%s<EOF>\n", response );
  612. }
  613. }