Guest User

ESP8266HTTPClient.cpp

a guest
Jul 22nd, 2022
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 42.17 KB | None | 0 0
  1. /**
  2. * ESP8266HTTPClient.cpp
  3. *
  4. * Created on: 02.11.2015
  5. *
  6. * Copyright (c) 2015 Markus Sattler. All rights reserved.
  7. * This file is part of the ESP8266HTTPClient for Arduino.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 2.1 of the License, or (at your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. */
  24. #include <Arduino.h>
  25.  
  26. #include "ESP8266HTTPClient.h"
  27.  
  28. #if HTTPCLIENT_1_1_COMPATIBLE
  29. #include <ESP8266WiFi.h>
  30. #include <WiFiClientSecureAxTLS.h>
  31. #endif
  32.  
  33. #include <StreamString.h>
  34. #include <base64.h>
  35.  
  36. #if HTTPCLIENT_1_1_COMPATIBLE
  37. class TransportTraits
  38. {
  39. public:
  40. virtual ~TransportTraits()
  41. {
  42. }
  43.  
  44. virtual std::unique_ptr<WiFiClient> create()
  45. {
  46. return std::unique_ptr<WiFiClient>(new WiFiClient());
  47. }
  48.  
  49. virtual bool verify(WiFiClient& client, const char* host)
  50. {
  51. (void)client;
  52. (void)host;
  53. return true;
  54. }
  55. };
  56.  
  57. class TLSTraits : public TransportTraits
  58. {
  59. public:
  60. TLSTraits(const String& fingerprint) :
  61. _fingerprint(fingerprint)
  62. {
  63. }
  64.  
  65. std::unique_ptr<WiFiClient> create() override
  66. {
  67. #pragma GCC diagnostic push
  68. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  69. return std::unique_ptr<WiFiClient>(new axTLS::WiFiClientSecure());
  70. #pragma GCC diagnostic pop
  71. }
  72.  
  73. bool verify(WiFiClient& client, const char* host) override
  74. {
  75. auto wcs = static_cast<axTLS::WiFiClientSecure&>(client);
  76. return wcs.verify(_fingerprint.c_str(), host);
  77. }
  78.  
  79. protected:
  80. String _fingerprint;
  81. };
  82.  
  83. class BearSSLTraits : public TransportTraits
  84. {
  85. public:
  86. BearSSLTraits(const uint8_t fingerprint[20])
  87. {
  88. memcpy(_fingerprint, fingerprint, sizeof(_fingerprint));
  89. }
  90.  
  91. std::unique_ptr<WiFiClient> create() override
  92. {
  93. BearSSL::WiFiClientSecure *client = new BearSSL::WiFiClientSecure();
  94. client->setFingerprint(_fingerprint);
  95. return std::unique_ptr<WiFiClient>(client);
  96. }
  97.  
  98. bool verify(WiFiClient& client, const char* host) override
  99. {
  100. // No-op. BearSSL will not connect if the fingerprint doesn't match.
  101. // So if you get to here you've already connected and it matched
  102. (void) client;
  103. (void) host;
  104. return true;
  105. }
  106.  
  107. protected:
  108. uint8_t _fingerprint[20];
  109. };
  110. #endif // HTTPCLIENT_1_1_COMPATIBLE
  111.  
  112. /**
  113. * constructor
  114. */
  115. HTTPClient::HTTPClient()
  116. : _client(nullptr), _userAgent(F("ESP8266HTTPClient"))
  117. {
  118. #if HTTPCLIENT_1_1_COMPATIBLE
  119. _tcpDeprecated.reset(nullptr);
  120. #endif
  121. }
  122.  
  123. /**
  124. * destructor
  125. */
  126. HTTPClient::~HTTPClient()
  127. {
  128. if(_client) {
  129. _client->stop();
  130. }
  131. if(_currentHeaders) {
  132. delete[] _currentHeaders;
  133. }
  134. }
  135.  
  136. void HTTPClient::clear()
  137. {
  138. _returnCode = 0;
  139. _size = -1;
  140. _headers = "";
  141. _payload.reset();
  142. _location = "";
  143. }
  144.  
  145.  
  146. /**
  147. * parsing the url for all needed parameters
  148. * @param client Client&
  149. * @param url String
  150. * @param https bool
  151. * @return success bool
  152. */
  153. bool HTTPClient::begin(WiFiClient &client, const String& url) {
  154. #if HTTPCLIENT_1_1_COMPATIBLE
  155. if(_tcpDeprecated) {
  156. DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
  157. _canReuse = false;
  158. end();
  159. }
  160. #endif
  161.  
  162. _client = &client;
  163.  
  164. // check for : (http: or https:)
  165. int index = url.indexOf(':');
  166. if(index < 0) {
  167. DEBUG_HTTPCLIENT("[HTTP-Client][begin] failed to parse protocol\n");
  168. return false;
  169. }
  170.  
  171. String protocol = url.substring(0, index);
  172. if(protocol != "http" && protocol != "https") {
  173. DEBUG_HTTPCLIENT("[HTTP-Client][begin] unknown protocol '%s'\n", protocol.c_str());
  174. return false;
  175. }
  176.  
  177. _port = (protocol == "https" ? 443 : 80);
  178. return beginInternal(url, protocol.c_str());
  179. }
  180.  
  181.  
  182. /**
  183. * directly supply all needed parameters
  184. * @param client Client&
  185. * @param host String
  186. * @param port uint16_t
  187. * @param uri String
  188. * @param https bool
  189. * @return success bool
  190. */
  191. bool HTTPClient::begin(WiFiClient &client, const String& host, uint16_t port, const String& uri, bool https)
  192. {
  193. #if HTTPCLIENT_1_1_COMPATIBLE
  194. if(_tcpDeprecated) {
  195. DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
  196. _canReuse = false;
  197. end();
  198. }
  199. #endif
  200.  
  201. _client = &client;
  202.  
  203. clear();
  204. _host = host;
  205. _port = port;
  206. _uri = uri;
  207. _protocol = (https ? "https" : "http");
  208. return true;
  209. }
  210.  
  211.  
  212. #if HTTPCLIENT_1_1_COMPATIBLE
  213. bool HTTPClient::begin(String url, String httpsFingerprint)
  214. {
  215. if(_client && !_tcpDeprecated) {
  216. DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
  217. _canReuse = false;
  218. end();
  219. }
  220.  
  221. if (httpsFingerprint.length() == 0) {
  222. return false;
  223. }
  224. if (!beginInternal(url, "https")) {
  225. return false;
  226. }
  227. _transportTraits = TransportTraitsPtr(new TLSTraits(httpsFingerprint));
  228. if(!_transportTraits) {
  229. DEBUG_HTTPCLIENT("[HTTP-Client][begin] could not create transport traits\n");
  230. return false;
  231. }
  232.  
  233. DEBUG_HTTPCLIENT("[HTTP-Client][begin] httpsFingerprint: %s\n", httpsFingerprint.c_str());
  234. return true;
  235. }
  236.  
  237.  
  238. bool HTTPClient::begin(String url, const uint8_t httpsFingerprint[20])
  239. {
  240. if(_client && !_tcpDeprecated) {
  241. DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
  242. _canReuse = false;
  243. end();
  244. }
  245.  
  246. if (!beginInternal(url, "https")) {
  247. return false;
  248. }
  249. _transportTraits = TransportTraitsPtr(new BearSSLTraits(httpsFingerprint));
  250. if(!_transportTraits) {
  251. DEBUG_HTTPCLIENT("[HTTP-Client][begin] could not create transport traits\n");
  252. return false;
  253. }
  254.  
  255. DEBUG_HTTPCLIENT("[HTTP-Client][begin] BearSSL-httpsFingerprint:");
  256. for (size_t i=0; i < 20; i++) {
  257. DEBUG_HTTPCLIENT(" %02x", httpsFingerprint[i]);
  258. }
  259. DEBUG_HTTPCLIENT("\n");
  260. return true;
  261. }
  262.  
  263.  
  264. /**
  265. * parsing the url for all needed parameters
  266. * @param url String
  267. */
  268. bool HTTPClient::begin(String url)
  269. {
  270. if(_client && !_tcpDeprecated) {
  271. DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
  272. _canReuse = false;
  273. end();
  274. }
  275.  
  276. if (!beginInternal(url, "http")) {
  277. return false;
  278. }
  279. _transportTraits = TransportTraitsPtr(new TransportTraits());
  280. return true;
  281. }
  282. #endif // HTTPCLIENT_1_1_COMPATIBLE
  283.  
  284. bool HTTPClient::beginInternal(const String& __url, const char* expectedProtocol)
  285. {
  286. String url(__url);
  287.  
  288. DEBUG_HTTPCLIENT("[HTTP-Client][begin] url: %s\n", url.c_str());
  289. clear();
  290.  
  291. // check for : (http: or https:
  292. int index = url.indexOf(':');
  293. if(index < 0) {
  294. DEBUG_HTTPCLIENT("[HTTP-Client][begin] failed to parse protocol\n");
  295. return false;
  296. }
  297.  
  298. _protocol = url.substring(0, index);
  299. url.remove(0, (index + 3)); // remove http:// or https://
  300.  
  301. if (_protocol == "http") {
  302. // set default port for 'http'
  303. _port = 80;
  304. } else if (_protocol == "https") {
  305. // set default port for 'https'
  306. _port = 443;
  307. } else {
  308. DEBUG_HTTPCLIENT("[HTTP-Client][begin] unsupported protocol: %s\n", _protocol.c_str());
  309. return false;
  310. }
  311.  
  312. index = url.indexOf('/');
  313. String host = url.substring(0, index);
  314. url.remove(0, index); // remove host part
  315.  
  316. // get Authorization
  317. index = host.indexOf('@');
  318. if(index >= 0) {
  319. // auth info
  320. String auth = host.substring(0, index);
  321. host.remove(0, index + 1); // remove auth part including @
  322. _base64Authorization = base64::encode(auth, false /* doNewLines */);
  323. }
  324.  
  325. // get port
  326. index = host.indexOf(':');
  327. if(index >= 0) {
  328. _host = host.substring(0, index); // hostname
  329. host.remove(0, (index + 1)); // remove hostname + :
  330. _port = host.toInt(); // get port
  331. } else {
  332. _host = host;
  333. }
  334. _uri = url;
  335.  
  336. if ( expectedProtocol != nullptr && _protocol != expectedProtocol) {
  337. DEBUG_HTTPCLIENT("[HTTP-Client][begin] unexpected protocol: %s, expected %s\n", _protocol.c_str(), expectedProtocol);
  338. return false;
  339. }
  340. DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port: %d url: %s\n", _host.c_str(), _port, _uri.c_str());
  341. return true;
  342. }
  343.  
  344. #if HTTPCLIENT_1_1_COMPATIBLE
  345. bool HTTPClient::begin(String host, uint16_t port, String uri)
  346. {
  347. if(_client && !_tcpDeprecated) {
  348. DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
  349. _canReuse = false;
  350. end();
  351. }
  352.  
  353. clear();
  354. _host = host;
  355. _port = port;
  356. _uri = uri;
  357. _transportTraits = TransportTraitsPtr(new TransportTraits());
  358. DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port: %d uri: %s\n", host.c_str(), port, uri.c_str());
  359. return true;
  360. }
  361.  
  362. #pragma GCC diagnostic push
  363. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  364. bool HTTPClient::begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint)
  365. {
  366. if (https) {
  367. return begin(host, port, uri, httpsFingerprint);
  368. } else {
  369. return begin(host, port, uri);
  370. }
  371. }
  372. #pragma GCC diagnostic pop
  373.  
  374. bool HTTPClient::begin(String host, uint16_t port, String uri, String httpsFingerprint)
  375. {
  376. if(_client && !_tcpDeprecated) {
  377. DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
  378. _canReuse = false;
  379. end();
  380. }
  381.  
  382. clear();
  383. _host = host;
  384. _port = port;
  385. _uri = uri;
  386.  
  387. if (httpsFingerprint.length() == 0) {
  388. return false;
  389. }
  390. _transportTraits = TransportTraitsPtr(new TLSTraits(httpsFingerprint));
  391. DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port: %d url: %s httpsFingerprint: %s\n", host.c_str(), port, uri.c_str(), httpsFingerprint.c_str());
  392. return true;
  393. }
  394.  
  395. bool HTTPClient::begin(String host, uint16_t port, String uri, const uint8_t httpsFingerprint[20])
  396. {
  397. if(_client && !_tcpDeprecated) {
  398. DEBUG_HTTPCLIENT("[HTTP-Client][begin] mix up of new and deprecated api\n");
  399. _canReuse = false;
  400. end();
  401. }
  402.  
  403. clear();
  404. _host = host;
  405. _port = port;
  406. _uri = uri;
  407.  
  408. _transportTraits = TransportTraitsPtr(new BearSSLTraits(httpsFingerprint));
  409. DEBUG_HTTPCLIENT("[HTTP-Client][begin] host: %s port: %d url: %s BearSSL-httpsFingerprint:", host.c_str(), port, uri.c_str());
  410. for (size_t i=0; i < 20; i++) {
  411. DEBUG_HTTPCLIENT(" %02x", httpsFingerprint[i]);
  412. }
  413. DEBUG_HTTPCLIENT("\n");
  414. return true;
  415. }
  416. #endif // HTTPCLIENT_1_1_COMPATIBLE
  417.  
  418. /**
  419. * end
  420. * called after the payload is handled
  421. */
  422. void HTTPClient::end(void)
  423. {
  424. disconnect(false);
  425. clear();
  426. _redirectCount = 0;
  427. }
  428.  
  429. /**
  430. * disconnect
  431. * close the TCP socket
  432. */
  433. void HTTPClient::disconnect(bool preserveClient)
  434. {
  435. if(connected()) {
  436. if(_client->available() > 0) {
  437. DEBUG_HTTPCLIENT("[HTTP-Client][end] still data in buffer (%d), clean up.\n", _client->available());
  438. while(_client->available() > 0) {
  439. _client->read();
  440. }
  441. }
  442.  
  443. if(_reuse && _canReuse) {
  444. DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp keep open for reuse\n");
  445. } else {
  446. DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp stop\n");
  447. if(_client) {
  448. _client->stop();
  449. if (!preserveClient) {
  450. _client = nullptr;
  451. }
  452. }
  453. #if HTTPCLIENT_1_1_COMPATIBLE
  454. if(_tcpDeprecated) {
  455. _transportTraits.reset(nullptr);
  456. _tcpDeprecated.reset(nullptr);
  457. }
  458. #endif
  459. }
  460. } else {
  461. DEBUG_HTTPCLIENT("[HTTP-Client][end] tcp is closed\n");
  462. }
  463. }
  464.  
  465. /**
  466. * connected
  467. * @return connected status
  468. */
  469. bool HTTPClient::connected()
  470. {
  471. if(_client) {
  472. return (_client->connected() || (_client->available() > 0));
  473. }
  474. return false;
  475. }
  476.  
  477. /**
  478. * try to reuse the connection to the server
  479. * keep-alive
  480. * @param reuse bool
  481. */
  482. void HTTPClient::setReuse(bool reuse)
  483. {
  484. _reuse = reuse;
  485. }
  486.  
  487. /**
  488. * set User Agent
  489. * @param userAgent const char *
  490. */
  491. void HTTPClient::setUserAgent(const String& userAgent)
  492. {
  493. _userAgent = userAgent;
  494. }
  495.  
  496. /**
  497. * set the Authorizatio for the http request
  498. * @param user const char *
  499. * @param password const char *
  500. */
  501. void HTTPClient::setAuthorization(const char * user, const char * password)
  502. {
  503. if(user && password) {
  504. String auth = user;
  505. auth += ':';
  506. auth += password;
  507. _base64Authorization = base64::encode(auth, false /* doNewLines */);
  508. }
  509. }
  510.  
  511. /**
  512. * set the Authorizatio for the http request
  513. * @param auth const char * base64
  514. */
  515. void HTTPClient::setAuthorization(const char * auth)
  516. {
  517. if(auth) {
  518. _base64Authorization = auth;
  519. _base64Authorization.replace(String('\n'), emptyString);
  520. }
  521. }
  522.  
  523. /**
  524. * set the timeout for the TCP connection
  525. * @param timeout unsigned int
  526. */
  527. void HTTPClient::setTimeout(uint16_t timeout)
  528. {
  529. _tcpTimeout = timeout;
  530. if(connected()) {
  531. _client->setTimeout(timeout);
  532. }
  533. }
  534.  
  535. /**
  536. * set the URL to a new value. Handy for following redirects.
  537. * @param url
  538. */
  539. bool HTTPClient::setURL(const String& url)
  540. {
  541. // if the new location is only a path then only update the URI
  542. if (url && url[0] == '/') {
  543. _uri = url;
  544. clear();
  545. return true;
  546. }
  547.  
  548. if (!url.startsWith(_protocol + ':')) {
  549. DEBUG_HTTPCLIENT("[HTTP-Client][setURL] new URL not the same protocol, expected '%s', URL: '%s'\n", _protocol.c_str(), url.c_str());
  550. return false;
  551. }
  552. // disconnect but preserve _client
  553. disconnect(true);
  554. return beginInternal(url, nullptr);
  555. }
  556.  
  557. /**
  558. * set true to follow redirects.
  559. * @param follow
  560. */
  561. void HTTPClient::setFollowRedirects(bool follow)
  562. {
  563. _followRedirects = follow;
  564. }
  565.  
  566. void HTTPClient::setRedirectLimit(uint16_t limit)
  567. {
  568. _redirectLimit = limit;
  569. }
  570.  
  571. /**
  572. * use HTTP1.0
  573. * @param useHTTP10 bool
  574. */
  575. void HTTPClient::useHTTP10(bool useHTTP10)
  576. {
  577. _useHTTP10 = useHTTP10;
  578. _reuse = !useHTTP10;
  579. }
  580.  
  581. /**
  582. * send a GET request
  583. * @return http code
  584. */
  585. int HTTPClient::GET()
  586. {
  587. return sendRequest("GET");
  588. }
  589.  
  590. /**
  591. * sends a post request to the server
  592. * @param payload const uint8_t *
  593. * @param size size_t
  594. * @return http code
  595. */
  596. int HTTPClient::POST(const uint8_t* payload, size_t size)
  597. {
  598. return sendRequest("POST", payload, size);
  599. }
  600.  
  601. int HTTPClient::POST(const String& payload)
  602. {
  603. return POST((uint8_t *) payload.c_str(), payload.length());
  604. }
  605.  
  606. /**
  607. * sends a put request to the server
  608. * @param payload uint8_t *
  609. * @param size size_t
  610. * @return http code
  611. */
  612. int HTTPClient::PUT(const uint8_t* payload, size_t size) {
  613. return sendRequest("PUT", payload, size);
  614. }
  615.  
  616. int HTTPClient::PUT(const String& payload) {
  617. return PUT((const uint8_t *) payload.c_str(), payload.length());
  618. }
  619.  
  620. /**
  621. * sends a patch request to the server
  622. * @param payload const uint8_t *
  623. * @param size size_t
  624. * @return http code
  625. */
  626. int HTTPClient::PATCH(const uint8_t * payload, size_t size) {
  627. return sendRequest("PATCH", payload, size);
  628. }
  629.  
  630. int HTTPClient::PATCH(const String& payload) {
  631. return PATCH((const uint8_t *) payload.c_str(), payload.length());
  632. }
  633.  
  634. /**
  635. * sendRequest
  636. * @param type const char * "GET", "POST", ....
  637. * @param payload String data for the message body
  638. * @return
  639. */
  640. int HTTPClient::sendRequest(const char * type, const String& payload)
  641. {
  642. return sendRequest(type, (const uint8_t *) payload.c_str(), payload.length());
  643. }
  644.  
  645. /**
  646. * sendRequest
  647. * @param type const char * "GET", "POST", ....
  648. * @param payload const uint8_t * data for the message body if null not send
  649. * @param size size_t size for the message body if 0 not send
  650. * @return -1 if no info or > 0 when Content-Length is set by server
  651. */
  652. int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t size)
  653. {
  654. bool redirect = false;
  655. int code = 0;
  656. do {
  657. // wipe out any existing headers from previous request
  658. for(size_t i = 0; i < _headerKeysCount; i++) {
  659. if (_currentHeaders[i].value.length() > 0) {
  660. _currentHeaders[i].value = "";
  661. }
  662. }
  663.  
  664. redirect = false;
  665. DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] type: '%s' redirCount: %d\n", type, _redirectCount);
  666.  
  667. // connect to server
  668. if(!connect()) {
  669. return returnError(HTTPC_ERROR_CONNECTION_REFUSED);
  670. }
  671.  
  672. addHeader(F("Content-Length"), String(payload && size > 0 ? size : 0));
  673.  
  674. // send Header
  675. if(!sendHeader(type)) {
  676. return returnError(HTTPC_ERROR_SEND_HEADER_FAILED);
  677. }
  678.  
  679. // send Payload if needed
  680. if (payload && size > 0) {
  681. size_t bytesWritten = 0;
  682. const uint8_t *p = payload;
  683. while (bytesWritten < size) {
  684. int written;
  685. int towrite = std::min((int)size, (int)HTTP_TCP_BUFFER_SIZE);
  686. written = _client->write(p + bytesWritten, towrite);
  687. if (written < 0) {
  688. return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
  689. } else if (written == 0) {
  690. return returnError(HTTPC_ERROR_CONNECTION_LOST);
  691. }
  692. bytesWritten += written;
  693. size -= written;
  694. }
  695. }
  696.  
  697. // handle Server Response (Header)
  698. code = handleHeaderResponse();
  699.  
  700. //
  701. // We can follow redirects for 301/302/307 for GET and HEAD requests and
  702. // and we have not exceeded the redirect limit preventing an infinite
  703. // redirect loop.
  704. //
  705. // https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
  706. //
  707. if (_followRedirects &&
  708. (_redirectCount < _redirectLimit) &&
  709. (_location.length() > 0) &&
  710. (code == 301 || code == 302 || code == 307) &&
  711. (!strcmp(type, "GET") || !strcmp(type, "HEAD"))
  712. ) {
  713. _redirectCount += 1; // increment the count for redirect.
  714. redirect = true;
  715. DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] following redirect:: '%s' redirCount: %d\n", _location.c_str(), _redirectCount);
  716. if (!setURL(_location)) {
  717. // return the redirect instead of handling on failure of setURL()
  718. redirect = false;
  719. }
  720. }
  721.  
  722. } while (redirect);
  723.  
  724. // handle 303 redirect for non GET/HEAD by changing to GET and requesting new url
  725. if (_followRedirects &&
  726. (_redirectCount < _redirectLimit) &&
  727. (_location.length() > 0) &&
  728. (code == 303) &&
  729. strcmp(type, "GET") && strcmp(type, "HEAD")
  730. ) {
  731. _redirectCount += 1;
  732. if (setURL(_location)) {
  733. code = sendRequest("GET");
  734. }
  735. }
  736.  
  737. // handle Server Response (Header)
  738. return returnError(code);
  739. }
  740.  
  741. /**
  742. * sendRequest
  743. * @param type const char * "GET", "POST", ....
  744. * @param stream Stream * data stream for the message body
  745. * @param size size_t size for the message body if 0 not Content-Length is send
  746. * @return -1 if no info or > 0 when Content-Length is set by server
  747. */
  748. int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size)
  749. {
  750.  
  751. if(!stream) {
  752. return returnError(HTTPC_ERROR_NO_STREAM);
  753. }
  754.  
  755. // connect to server
  756. if(!connect()) {
  757. return returnError(HTTPC_ERROR_CONNECTION_REFUSED);
  758. }
  759.  
  760. if(size > 0) {
  761. addHeader("Content-Length", String(size));
  762. }
  763.  
  764. // send Header
  765. if(!sendHeader(type)) {
  766. return returnError(HTTPC_ERROR_SEND_HEADER_FAILED);
  767. }
  768.  
  769. int buff_size = HTTP_TCP_BUFFER_SIZE;
  770.  
  771. int len = size;
  772. int bytesWritten = 0;
  773.  
  774. if(len == 0) {
  775. len = -1;
  776. }
  777.  
  778. // if possible create smaller buffer then HTTP_TCP_BUFFER_SIZE
  779. if((len > 0) && (len < HTTP_TCP_BUFFER_SIZE)) {
  780. buff_size = len;
  781. }
  782.  
  783. // create buffer for read
  784. uint8_t * buff = (uint8_t *) malloc(buff_size);
  785.  
  786. if(buff) {
  787. // read all data from stream and send it to server
  788. while(connected() && (stream->available() > 0) && (len > 0 || len == -1)) {
  789.  
  790. // get available data size
  791. int sizeAvailable = stream->available();
  792.  
  793. if(sizeAvailable) {
  794.  
  795. int readBytes = sizeAvailable;
  796.  
  797. // read only the asked bytes
  798. if(len > 0 && readBytes > len) {
  799. readBytes = len;
  800. }
  801.  
  802. // not read more the buffer can handle
  803. if(readBytes > buff_size) {
  804. readBytes = buff_size;
  805. }
  806.  
  807. // read data
  808. int bytesRead = stream->readBytes(buff, readBytes);
  809.  
  810. // write it to Stream
  811. int bytesWrite = _client->write((const uint8_t *) buff, bytesRead);
  812. bytesWritten += bytesWrite;
  813.  
  814. // are all Bytes a writen to stream ?
  815. if(bytesWrite != bytesRead) {
  816. DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] short write, asked for %d but got %d retry...\n", bytesRead, bytesWrite);
  817.  
  818. // check for write error
  819. if(_client->getWriteError()) {
  820. DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] stream write error %d\n", _client->getWriteError());
  821.  
  822. //reset write error for retry
  823. _client->clearWriteError();
  824. }
  825.  
  826. // some time for the stream
  827. delay(1);
  828.  
  829. int leftBytes = (readBytes - bytesWrite);
  830.  
  831. // retry to send the missed bytes
  832. bytesWrite = _client->write((const uint8_t *) (buff + bytesWrite), leftBytes);
  833. bytesWritten += bytesWrite;
  834.  
  835. if(bytesWrite != leftBytes) {
  836. // failed again
  837. DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] short write, asked for %d but got %d failed.\n", leftBytes, bytesWrite);
  838. free(buff);
  839. return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
  840. }
  841. }
  842.  
  843. // check for write error
  844. if(_client->getWriteError()) {
  845. DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] stream write error %d\n", _client->getWriteError());
  846. free(buff);
  847. return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
  848. }
  849.  
  850. // count bytes to read left
  851. if(len > 0) {
  852. len -= readBytes;
  853. }
  854.  
  855. delay(0);
  856. } else {
  857. delay(1);
  858. }
  859. }
  860.  
  861. free(buff);
  862.  
  863. if(size && (int) size != bytesWritten) {
  864. DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] Stream payload bytesWritten %d and size %zd mismatch!.\n", bytesWritten, size);
  865. DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] ERROR SEND PAYLOAD FAILED!");
  866. return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
  867. } else {
  868. DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] Stream payload written: %d\n", bytesWritten);
  869. }
  870.  
  871. } else {
  872. DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] not enough ram! need %d\n", HTTP_TCP_BUFFER_SIZE);
  873. return returnError(HTTPC_ERROR_TOO_LESS_RAM);
  874. }
  875.  
  876. // handle Server Response (Header)
  877. return returnError(handleHeaderResponse());
  878. }
  879.  
  880. /**
  881. * size of message body / payload
  882. * @return -1 if no info or > 0 when Content-Length is set by server
  883. */
  884. int HTTPClient::getSize(void)
  885. {
  886. return _size;
  887. }
  888.  
  889. /**
  890. * Location if redirect
  891. */
  892. const String& HTTPClient::getLocation(void)
  893. {
  894. return _location;
  895. }
  896.  
  897. /**
  898. * returns the stream of the tcp connection
  899. * @return WiFiClient
  900. */
  901. WiFiClient& HTTPClient::getStream(void)
  902. {
  903. if(connected()) {
  904. return *_client;
  905. }
  906.  
  907. DEBUG_HTTPCLIENT("[HTTP-Client] getStream: not connected\n");
  908. static WiFiClient empty;
  909. return empty;
  910. }
  911.  
  912. /**
  913. * returns the stream of the tcp connection
  914. * @return WiFiClient *
  915. */
  916. WiFiClient* HTTPClient::getStreamPtr(void)
  917. {
  918. if(connected()) {
  919. return _client;
  920. }
  921.  
  922. DEBUG_HTTPCLIENT("[HTTP-Client] getStreamPtr: not connected\n");
  923. return nullptr;
  924. }
  925.  
  926. /**
  927. * write all message body / payload to Stream
  928. * @param stream Stream *
  929. * @return bytes written ( negative values are error codes )
  930. */
  931. int HTTPClient::writeToStream(Stream * stream)
  932. {
  933.  
  934. if(!stream) {
  935. return returnError(HTTPC_ERROR_NO_STREAM);
  936. }
  937.  
  938. if(!connected()) {
  939. return returnError(HTTPC_ERROR_NOT_CONNECTED);
  940. }
  941.  
  942. // get length of document (is -1 when Server sends no Content-Length header)
  943. int len = _size;
  944. int ret = 0;
  945.  
  946. if(_transferEncoding == HTTPC_TE_IDENTITY) {
  947. ret = writeToStreamDataBlock(stream, len);
  948.  
  949. // have we an error?
  950. if(ret < 0) {
  951. return returnError(ret);
  952. }
  953. } else if(_transferEncoding == HTTPC_TE_CHUNKED) {
  954. int size = 0;
  955. while(1) {
  956. if(!connected()) {
  957. return returnError(HTTPC_ERROR_CONNECTION_LOST);
  958. }
  959. String chunkHeader = _client->readStringUntil('\n');
  960.  
  961. if(chunkHeader.length() <= 0) {
  962. return returnError(HTTPC_ERROR_READ_TIMEOUT);
  963. }
  964.  
  965. chunkHeader.trim(); // remove \r
  966.  
  967. // read size of chunk
  968. len = (uint32_t) strtol((const char *) chunkHeader.c_str(), NULL, 16);
  969. size += len;
  970. DEBUG_HTTPCLIENT("[HTTP-Client] read chunk len: %d\n", len);
  971.  
  972. // data left?
  973. if(len > 0) {
  974. int r = writeToStreamDataBlock(stream, len);
  975. if(r < 0) {
  976. // error in writeToStreamDataBlock
  977. return returnError(r);
  978. }
  979. ret += r;
  980. } else {
  981.  
  982. // if no length Header use global chunk size
  983. if(_size <= 0) {
  984. _size = size;
  985. }
  986.  
  987. // check if we have write all data out
  988. if(ret != _size) {
  989. return returnError(HTTPC_ERROR_STREAM_WRITE);
  990. }
  991. break;
  992. }
  993.  
  994. // read trailing \r\n at the end of the chunk
  995. char buf[2];
  996. auto trailing_seq_len = _client->readBytes((uint8_t*)buf, 2);
  997. if (trailing_seq_len != 2 || buf[0] != '\r' || buf[1] != '\n') {
  998. return returnError(HTTPC_ERROR_READ_TIMEOUT);
  999. }
  1000.  
  1001. delay(0);
  1002. }
  1003. } else {
  1004. return returnError(HTTPC_ERROR_ENCODING);
  1005. }
  1006.  
  1007. disconnect(true);
  1008. return ret;
  1009. }
  1010.  
  1011. /**
  1012. * return all payload as String (may need lot of ram or trigger out of memory!)
  1013. * @return String
  1014. */
  1015. const String& HTTPClient::getString(void)
  1016. {
  1017. if (_payload) {
  1018. return *_payload;
  1019. }
  1020.  
  1021. _payload.reset(new StreamString());
  1022.  
  1023. if(_size > 0) {
  1024. // try to reserve needed memmory
  1025. if(!_payload->reserve((_size + 1))) {
  1026. DEBUG_HTTPCLIENT("[HTTP-Client][getString] not enough memory to reserve a string! need: %d\n", (_size + 1));
  1027. return *_payload;
  1028. }
  1029. }
  1030.  
  1031. writeToStream(_payload.get());
  1032. return *_payload;
  1033. }
  1034.  
  1035. /**
  1036. * converts error code to String
  1037. * @param error int
  1038. * @return String
  1039. */
  1040. String HTTPClient::errorToString(int error)
  1041. {
  1042. switch(error) {
  1043. case HTTPC_ERROR_CONNECTION_REFUSED:
  1044. return F("connection refused");
  1045. case HTTPC_ERROR_SEND_HEADER_FAILED:
  1046. return F("send header failed");
  1047. case HTTPC_ERROR_SEND_PAYLOAD_FAILED:
  1048. return F("send payload failed");
  1049. case HTTPC_ERROR_NOT_CONNECTED:
  1050. return F("not connected");
  1051. case HTTPC_ERROR_CONNECTION_LOST:
  1052. return F("connection lost");
  1053. case HTTPC_ERROR_NO_STREAM:
  1054. return F("no stream");
  1055. case HTTPC_ERROR_NO_HTTP_SERVER:
  1056. return F("no HTTP server");
  1057. case HTTPC_ERROR_TOO_LESS_RAM:
  1058. return F("not enough ram");
  1059. case HTTPC_ERROR_ENCODING:
  1060. return F("Transfer-Encoding not supported");
  1061. case HTTPC_ERROR_STREAM_WRITE:
  1062. return F("Stream write error");
  1063. case HTTPC_ERROR_READ_TIMEOUT:
  1064. return F("read Timeout");
  1065. default:
  1066. return String();
  1067. }
  1068. }
  1069.  
  1070. /**
  1071. * adds Header to the request
  1072. * @param name
  1073. * @param value
  1074. * @param first
  1075. */
  1076. void HTTPClient::addHeader(const String& name, const String& value, bool first, bool replace)
  1077. {
  1078. // not allow set of Header handled by code
  1079. if(!name.equalsIgnoreCase(F("Connection")) &&
  1080. !name.equalsIgnoreCase(F("User-Agent")) &&
  1081. !name.equalsIgnoreCase(F("Host")) &&
  1082. !(name.equalsIgnoreCase(F("Authorization")) && _base64Authorization.length())){
  1083.  
  1084. String headerLine = name;
  1085. headerLine += ": ";
  1086.  
  1087. if (replace) {
  1088. int headerStart = _headers.indexOf(headerLine);
  1089. if (headerStart != -1) {
  1090. int headerEnd = _headers.indexOf('\n', headerStart);
  1091. _headers = _headers.substring(0, headerStart) + _headers.substring(headerEnd + 1);
  1092. }
  1093. }
  1094.  
  1095. headerLine += value;
  1096. headerLine += "\r\n";
  1097. if(first) {
  1098. _headers = headerLine + _headers;
  1099. } else {
  1100. _headers += headerLine;
  1101. }
  1102. }
  1103.  
  1104. }
  1105.  
  1106. void HTTPClient::collectHeaders(const char* headerKeys[], const size_t headerKeysCount)
  1107. {
  1108. _headerKeysCount = headerKeysCount;
  1109. if(_currentHeaders) {
  1110. delete[] _currentHeaders;
  1111. }
  1112. _currentHeaders = new RequestArgument[_headerKeysCount];
  1113. for(size_t i = 0; i < _headerKeysCount; i++) {
  1114. _currentHeaders[i].key = headerKeys[i];
  1115. }
  1116. }
  1117.  
  1118. String HTTPClient::header(const char* name)
  1119. {
  1120. for(size_t i = 0; i < _headerKeysCount; ++i) {
  1121. if(_currentHeaders[i].key == name) {
  1122. return _currentHeaders[i].value;
  1123. }
  1124. }
  1125. return String();
  1126. }
  1127.  
  1128. String HTTPClient::header(size_t i)
  1129. {
  1130. if(i < _headerKeysCount) {
  1131. return _currentHeaders[i].value;
  1132. }
  1133. return String();
  1134. }
  1135.  
  1136. String HTTPClient::headerName(size_t i)
  1137. {
  1138. if(i < _headerKeysCount) {
  1139. return _currentHeaders[i].key;
  1140. }
  1141. return String();
  1142. }
  1143.  
  1144. int HTTPClient::headers()
  1145. {
  1146. return _headerKeysCount;
  1147. }
  1148.  
  1149. bool HTTPClient::hasHeader(const char* name)
  1150. {
  1151. for(size_t i = 0; i < _headerKeysCount; ++i) {
  1152. if((_currentHeaders[i].key == name) && (_currentHeaders[i].value.length() > 0)) {
  1153. return true;
  1154. }
  1155. }
  1156. return false;
  1157. }
  1158.  
  1159. /**
  1160. * init TCP connection and handle ssl verify if needed
  1161. * @return true if connection is ok
  1162. */
  1163. bool HTTPClient::connect(void)
  1164. {
  1165. if(connected()) {
  1166. if(_reuse) {
  1167. DEBUG_HTTPCLIENT("[HTTP-Client] connect: already connected, reusing connection\n");
  1168. } else {
  1169. DEBUG_HTTPCLIENT("[HTTP-Client] connect: already connected, try reuse!\n");
  1170. }
  1171. while(_client->available() > 0) {
  1172. _client->read();
  1173. }
  1174. return true;
  1175. }
  1176.  
  1177. #if HTTPCLIENT_1_1_COMPATIBLE
  1178. if(!_client && _transportTraits) {
  1179. _tcpDeprecated = _transportTraits->create();
  1180. if(!_tcpDeprecated) {
  1181. DEBUG_HTTPCLIENT("[HTTP-Client] connect: could not create tcp\n");
  1182. return false;
  1183. }
  1184. _client = _tcpDeprecated.get();
  1185. }
  1186. #endif
  1187.  
  1188. if(!_client) {
  1189. DEBUG_HTTPCLIENT("[HTTP-Client] connect: HTTPClient::begin was not called or returned error\n");
  1190. return false;
  1191. }
  1192.  
  1193. _client->setTimeout(_tcpTimeout);
  1194.  
  1195. if(!_client->connect(_host.c_str(), _port)) {
  1196. DEBUG_HTTPCLIENT("[HTTP-Client] failed connect to %s:%u\n", _host.c_str(), _port);
  1197. return false;
  1198. }
  1199.  
  1200. DEBUG_HTTPCLIENT("[HTTP-Client] connected to %s:%u\n", _host.c_str(), _port);
  1201.  
  1202. #if HTTPCLIENT_1_1_COMPATIBLE
  1203. if (_tcpDeprecated && !_transportTraits->verify(*_tcpDeprecated, _host.c_str())) {
  1204. DEBUG_HTTPCLIENT("[HTTP-Client] transport level verify failed\n");
  1205. _client->stop();
  1206. return false;
  1207. }
  1208. #endif
  1209.  
  1210.  
  1211. #ifdef ESP8266
  1212. _client->setNoDelay(true);
  1213. #endif
  1214. return connected();
  1215. }
  1216.  
  1217. /**
  1218. * sends HTTP request header
  1219. * @param type (GET, POST, ...)
  1220. * @return status
  1221. */
  1222. bool HTTPClient::sendHeader(const char * type)
  1223. {
  1224. if(!connected()) {
  1225. return false;
  1226. }
  1227.  
  1228. String header = String(type) + ' ' + (_uri.length() ? _uri : F("/")) + F(" HTTP/1.");
  1229.  
  1230. if(_useHTTP10) {
  1231. header += '0';
  1232. } else {
  1233. header += '1';
  1234. }
  1235.  
  1236. header += String(F("\r\nHost: ")) + _host;
  1237. if (_port != 80 && _port != 443)
  1238. {
  1239. header += ':';
  1240. header += String(_port);
  1241. }
  1242. header += String(F("\r\nUser-Agent: ")) + _userAgent +
  1243. F("\r\nConnection: ");
  1244.  
  1245. if(_reuse) {
  1246. header += F("keep-alive");
  1247. } else {
  1248. header += F("close");
  1249. }
  1250. header += "\r\n";
  1251.  
  1252. if(!_useHTTP10) {
  1253. header += F("Accept-Encoding: identity;q=1,chunked;q=0.1,*;q=0\r\n");
  1254. }
  1255.  
  1256. if(_base64Authorization.length()) {
  1257. header += F("Authorization: Basic ");
  1258. header += _base64Authorization;
  1259. header += "\r\n";
  1260. }
  1261.  
  1262. header += _headers + "\r\n";
  1263.  
  1264. DEBUG_HTTPCLIENT("[HTTP-Client] sending request header\n-----\n%s-----\n", header.c_str());
  1265.  
  1266. return (_client->write((const uint8_t *) header.c_str(), header.length()) == header.length());
  1267. }
  1268.  
  1269. /**
  1270. * reads the response from the server
  1271. * @return int http code
  1272. */
  1273. int HTTPClient::handleHeaderResponse()
  1274. {
  1275.  
  1276. if(!connected()) {
  1277. return HTTPC_ERROR_NOT_CONNECTED;
  1278. }
  1279.  
  1280. clear();
  1281.  
  1282. _canReuse = _reuse;
  1283.  
  1284. String transferEncoding;
  1285.  
  1286. _transferEncoding = HTTPC_TE_IDENTITY;
  1287. unsigned long lastDataTime = millis();
  1288.  
  1289. while(connected()) {
  1290. size_t len = _client->available();
  1291. if(len > 0) {
  1292. String headerLine = _client->readStringUntil('\n');
  1293. headerLine.trim(); // remove \r
  1294.  
  1295. lastDataTime = millis();
  1296.  
  1297. DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] RX: '%s'\n", headerLine.c_str());
  1298.  
  1299. if(headerLine.startsWith("HTTP/1.")) {
  1300. if(_canReuse) {
  1301. _canReuse = (headerLine[sizeof "HTTP/1." - 1] != '0');
  1302. }
  1303. _returnCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt();
  1304. } else if(headerLine.indexOf(':')) {
  1305. String headerName = headerLine.substring(0, headerLine.indexOf(':'));
  1306. String headerValue = headerLine.substring(headerLine.indexOf(':') + 1);
  1307. headerValue.trim();
  1308.  
  1309. if(headerName.equalsIgnoreCase(F("Content-Length"))) {
  1310. _size = headerValue.toInt();
  1311. }
  1312.  
  1313. if(_canReuse && headerName.equalsIgnoreCase(F("Connection"))) {
  1314. if(headerValue.indexOf("close") >= 0 && headerValue.indexOf("keep-alive") < 0) {
  1315. _canReuse = false;
  1316. }
  1317. }
  1318.  
  1319. if(headerName.equalsIgnoreCase(F("Transfer-Encoding"))) {
  1320. transferEncoding = headerValue;
  1321. }
  1322.  
  1323. if(headerName.equalsIgnoreCase(F("Location"))) {
  1324. _location = headerValue;
  1325. }
  1326.  
  1327. for(size_t i = 0; i < _headerKeysCount; i++) {
  1328. if(_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
  1329. if (_currentHeaders[i].value != "") {
  1330. // Existing value, append this one with a comma
  1331. _currentHeaders[i].value += ',';
  1332. _currentHeaders[i].value += headerValue;
  1333. } else {
  1334. _currentHeaders[i].value = headerValue;
  1335. }
  1336. break; // We found a match, stop looking
  1337. }
  1338. }
  1339. }
  1340.  
  1341. if(headerLine == "") {
  1342. DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] code: %d\n", _returnCode);
  1343.  
  1344. if(_size > 0) {
  1345. DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] size: %d\n", _size);
  1346. }
  1347.  
  1348. if(transferEncoding.length() > 0) {
  1349. DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] Transfer-Encoding: %s\n", transferEncoding.c_str());
  1350. if(transferEncoding.equalsIgnoreCase(F("chunked"))) {
  1351. _transferEncoding = HTTPC_TE_CHUNKED;
  1352. } else {
  1353. return HTTPC_ERROR_ENCODING;
  1354. }
  1355. } else {
  1356. _transferEncoding = HTTPC_TE_IDENTITY;
  1357. }
  1358.  
  1359. if(_returnCode) {
  1360. return _returnCode;
  1361. } else {
  1362. DEBUG_HTTPCLIENT("[HTTP-Client][handleHeaderResponse] Remote host is not an HTTP Server!");
  1363. return HTTPC_ERROR_NO_HTTP_SERVER;
  1364. }
  1365. }
  1366.  
  1367. } else {
  1368. if((millis() - lastDataTime) > _tcpTimeout) {
  1369. return HTTPC_ERROR_READ_TIMEOUT;
  1370. }
  1371. delay(0);
  1372. }
  1373. }
  1374.  
  1375. return HTTPC_ERROR_CONNECTION_LOST;
  1376. }
  1377.  
  1378. /**
  1379. * write one Data Block to Stream
  1380. * @param stream Stream *
  1381. * @param size int
  1382. * @return < 0 = error >= 0 = size written
  1383. */
  1384. int HTTPClient::writeToStreamDataBlock(Stream * stream, int size)
  1385. {
  1386. int buff_size = HTTP_TCP_BUFFER_SIZE;
  1387. int len = size; // left size to read
  1388. int bytesWritten = 0;
  1389.  
  1390. // if possible create smaller buffer then HTTP_TCP_BUFFER_SIZE
  1391. if((len > 0) && (len < HTTP_TCP_BUFFER_SIZE)) {
  1392. buff_size = len;
  1393. }
  1394.  
  1395. // create buffer for read
  1396. uint8_t * buff = (uint8_t *) malloc(buff_size);
  1397.  
  1398. if(!buff) {
  1399. DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] not enough ram! need %d\n", HTTP_TCP_BUFFER_SIZE);
  1400. return HTTPC_ERROR_TOO_LESS_RAM;
  1401. }
  1402.  
  1403. // read all data from server
  1404. while(connected() && (len > 0 || len == -1))
  1405. {
  1406. int readBytes = len;
  1407.  
  1408. // not read more the buffer can handle
  1409. if(readBytes > buff_size) {
  1410. readBytes = buff_size;
  1411. }
  1412.  
  1413. // read data
  1414. int bytesRead = _client->readBytes(buff, readBytes);
  1415. if (!bytesRead)
  1416. {
  1417. DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] input stream timeout\n");
  1418. free(buff);
  1419. return HTTPC_ERROR_READ_TIMEOUT;
  1420. }
  1421.  
  1422. // write it to Stream
  1423. int bytesWrite = stream->write(buff, bytesRead);
  1424. bytesWritten += bytesWrite;
  1425.  
  1426. // are all Bytes a writen to stream ?
  1427. if(bytesWrite != bytesRead) {
  1428. DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] short write asked for %d but got %d retry...\n", bytesRead, bytesWrite);
  1429.  
  1430. // check for write error
  1431. if(stream->getWriteError()) {
  1432. DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] stream write error %d\n", stream->getWriteError());
  1433.  
  1434. //reset write error for retry
  1435. stream->clearWriteError();
  1436. }
  1437.  
  1438. // some time for the stream
  1439. delay(1);
  1440.  
  1441. int leftBytes = (bytesRead - bytesWrite);
  1442.  
  1443. // retry to send the missed bytes
  1444. bytesWrite = stream->write((buff + bytesWrite), leftBytes);
  1445. bytesWritten += bytesWrite;
  1446.  
  1447. if(bytesWrite != leftBytes) {
  1448. // failed again
  1449. DEBUG_HTTPCLIENT("[HTTP-Client][writeToStream] short write asked for %d but got %d failed.\n", leftBytes, bytesWrite);
  1450. free(buff);
  1451. return HTTPC_ERROR_STREAM_WRITE;
  1452. }
  1453. }
  1454.  
  1455. // check for write error
  1456. if(stream->getWriteError()) {
  1457. DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] stream write error %d\n", stream->getWriteError());
  1458. free(buff);
  1459. return HTTPC_ERROR_STREAM_WRITE;
  1460. }
  1461.  
  1462. // count bytes to read left
  1463. if(len > 0) {
  1464. len -= bytesRead;
  1465. }
  1466.  
  1467. delay(0);
  1468. }
  1469.  
  1470. free(buff);
  1471.  
  1472. DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] end of chunk or data (transferred: %d).\n", bytesWritten);
  1473.  
  1474. if((size > 0) && (size != bytesWritten)) {
  1475. DEBUG_HTTPCLIENT("[HTTP-Client][writeToStreamDataBlock] transferred size %d and request size %d mismatch!.\n", bytesWritten, size);
  1476. return HTTPC_ERROR_STREAM_WRITE;
  1477. }
  1478.  
  1479. return bytesWritten;
  1480. }
  1481.  
  1482. /**
  1483. * called to handle error return, may disconnect the connection if still exists
  1484. * @param error
  1485. * @return error
  1486. */
  1487. int HTTPClient::returnError(int error)
  1488. {
  1489. if(error < 0) {
  1490. DEBUG_HTTPCLIENT("[HTTP-Client][returnError] error(%d): %s\n", error, errorToString(error).c_str());
  1491. if(connected()) {
  1492. DEBUG_HTTPCLIENT("[HTTP-Client][returnError] tcp stop\n");
  1493. _client->stop();
  1494. }
  1495. }
  1496. return error;
  1497. }
  1498.  
Add Comment
Please, Sign In to add comment