int HttpClient::skipResponseHeaders() { // Just keep reading until we finish reading the headers or time out unsigned long timeoutStart = millis(); // Whilst we haven't timed out & haven't reached the end of the headers while ((!endOfHeadersReached()) && ( (millis() - timeoutStart) < iHttpResponseTimeout )) { if (available()) { (void)readHeader(); // We read something, reset the timeout counter timeoutStart = millis(); } else { // We haven't got any data, so let's pause to allow some to // arrive delay(kHttpWaitForDataDelay); } } if (endOfHeadersReached()) { // Success return HTTP_SUCCESS; } else { // We must've timed out return HTTP_ERROR_TIMED_OUT; } }
int HttpClient::read() { #if 0 // Fails on WiFi because multi-byte read seems to be broken uint8_t b[1]; int ret = read(b, 1); if (ret == 1) { return b[0]; } else { return -1; } #else int ret = iClient->read(); if (ret >= 0) { if (endOfHeadersReached() && iContentLength > 0) { // We're outputting the body now and we've seen a Content-Length header // So keep track of how many bytes are left iBodyLengthConsumed++; } } return ret; #endif }
bool HttpClient::headerAvailable() { // clear the currently store header line iHeaderLine = ""; while (!endOfHeadersReached()) { // read a byte from the header int c = readHeader(); if (c == '\r' || c == '\n') { if (iHeaderLine.length()) { // end of the line, all done break; } else { // ignore any CR or LF characters continue; } } // append byte to header line iHeaderLine += (char)c; } return (iHeaderLine.length() > 0); }
int HttpClient::read() { if (iIsChunked && !available()) { return -1; } int ret = iClient->read(); if (ret >= 0) { if (endOfHeadersReached() && iContentLength > 0) { // We're outputting the body now and we've seen a Content-Length header // So keep track of how many bytes are left iBodyLengthConsumed++; } if (iState == eReadingBodyChunk) { iChunkLength--; if (iChunkLength == 0) { iState = eReadingChunkLength; } } } return ret; }
bool HttpClient::endOfBodyReached() { if (endOfHeadersReached() && (contentLength() != kNoContentLengthHeader)) { // We've got to the body and we know how long it will be return (iBodyLengthConsumed >= contentLength()); } return false; }
int HttpClient::contentLength() { // skip the response headers, if they haven't been read already if (!endOfHeadersReached()) { skipResponseHeaders(); } return iContentLength; }
int HttpClient::read(uint8_t *buf, size_t size) { int ret =iClient->read(buf, size); if (endOfHeadersReached() && iContentLength > 0) { // We're outputting the body now and we've seen a Content-Length header // So keep track of how many bytes are left if (ret >= 0) { iBodyLengthConsumed += ret; } } return ret; }
int HttpClient::readHeader() { char c = read(); if (endOfHeadersReached()) { // We've passed the headers, but rather than return an error, we'll just // act as a slightly less efficient version of read() return c; } // Whilst reading out the headers to whoever wants them, we'll keep an // eye out for the "Content-Length" header switch(iState) { case eStatusCodeRead: // We're at the start of a line, or somewhere in the middle of reading // the Content-Length prefix if (*iContentLengthPtr == c) { // This character matches, just move along iContentLengthPtr++; if (*iContentLengthPtr == '\0') { // We've reached the end of the prefix iState = eReadingContentLength; // Just in case we get multiple Content-Length headers, this // will ensure we just get the value of the last one iContentLength = 0; } } else if ((iContentLengthPtr == kContentLengthPrefix) && (c == '\r')) { // We've found a '\r' at the start of a line, so this is probably // the end of the headers iState = eLineStartingCRFound; } else { // This isn't the Content-Length header, skip to the end of the line iState = eSkipToEndOfHeader; } break; case eReadingContentLength: if (isdigit(c)) { iContentLength = iContentLength*10 + (c - '0'); } else { // We've reached the end of the content length // We could sanity check it here or double-check for "\r\n" // rather than anything else, but let's be lenient iState = eSkipToEndOfHeader; } break; case eLineStartingCRFound: if (c == '\n') { iState = eReadingBody; } break; default: // We're just waiting for the end of the line now break; }; if ( (c == '\n') && !endOfHeadersReached() ) { // We've got to the end of this line, start processing again iState = eStatusCodeRead; iContentLengthPtr = kContentLengthPrefix; } // And return the character read to whoever wants it return c; }