int JSONAPI::request ( js0n_user_cb_t cb ) {
  if (this->hasBody) {
    wifly.println("0");
    wifly.println();
  }
  
  js0n_parser_t parser;
  parser.buffer = this->buffer;
  parser.stream = &wifly;
  parser.user_cb = cb;
  
  int status_code = 0;
  readResponseHeaders(&status_code, (int *) &parser.length);
  if (status_code != 0 && status_code < 500) {
    int parse_status = js0n_parse ( &parser );
  }
  return status_code;
}
Exemple #2
0
int HttpConnection::request(InputStream& data, OutputStream& response, bool log_request)
{
    int readBytes = 0; 
    int totalBytesRead = 0;
    DWORD bytesWritten = 0;
    int ret = HTTP_STATUS_OK;
    WString headers;
    bool sendDataAtOnce = false;
    char *chunkToSend = NULL;
    int64_t contentLen = 0; 
    INTERNET_BUFFERS BufferIn = {0};
    DWORD errorCode = 0;
    char tmpbuff[1024];

#ifdef USE_ZLIB
    Bytef* cBuf = NULL;
    uLong  cBufLen  = 0;
    int64_t uncompressedContentLen = 0;
#endif
    
    // Timeout to receive a rensponse from server (default = 30 sec).
    DWORD reqTimeoutMsec = requestTimeout * 1000;
    DWORD resTimeoutMsec = responseTimeout == 0 ? 30 * 1000 : responseTimeout * 1000;
    InternetSetOption(req, INTERNET_OPTION_RECEIVE_TIMEOUT, &reqTimeoutMsec, sizeof(DWORD));
    InternetSetOption(req, INTERNET_OPTION_SEND_TIMEOUT,    &resTimeoutMsec, sizeof(DWORD));
    // InternetSetOption(req, SECURITY_FLAG_IGNORE_REVOCATION, NULL, 0);
    
    if (auth) {
        if (auth->getType() == HttpAuthentication::Basic) {
           StringBuffer authCred = auth->getAuthenticationHeaders();
           StringBuffer authHeader;
           authHeader.sprintf("Basic %s", authCred.c_str());

           setRequestHeader(HTTP_HEADER_AUTHORIZATION, authHeader);
        } else {
            LOG.error("%s: authentication type not supported [%d]", __FUNCTION__, auth->getType());
            return StatusInternalError;
        }
    }

    // For user agent, content length and accept encoding, override property
    // values, even if set by the caller.
    setRequestHeader(HTTP_HEADER_USER_AGENT, userAgent);
    
    contentLen = data.getTotalSize() - data.getPosition();

#ifdef USE_ZLIB
    if (compression_enabled) {
        chunkToSend = new char [contentLen];   

        if (data.read((void *)chunkToSend, contentLen) != contentLen) {
            LOG.error("error reading data from input stream");  
            delete [] chunkToSend;
            return StatusInternalError;
        }

        sendDataAtOnce = true;

        cBufLen = contentLen;

        // DEFLATE (compress data)
        cBuf =  new Bytef[contentLen];
 
        // compress the source buffer into the destination buffer.
        int err = compress(cBuf, &cBufLen, (Bytef*)chunkToSend, contentLen);

        if (err != Z_OK) {
            LOG.error("%s: error compressing data buffer [%d]", __FUNCTION__, err);

            setError(ERR_HTTP_DEFLATE, "ZLIB: error occurred compressing data.");
            delete [] chunkToSend;
            delete [] cBuf;

            return StatusInternalError;
        }
        
        uncompressedContentLen = contentLen;
        contentLen = cBufLen;

       
        sprintf(tmpbuff, "%llu", contentLen); 
        setRequestHeader(HTTP_HEADER_CONTENT_LENGTH, tmpbuff);
        setRequestHeader(HTTP_HEADER_ACCEPT_ENCODING, "deflate");
        setRequestHeader(HTTP_HEADER_CONTENT_ENCODING, "deflate");

        sprintf(tmpbuff, "%llu", uncompressedContentLen); 
        setRequestHeader(HTTP_HEADER_UNCOMPRESSED_CONTENT_LENGTH, tmpbuff);
    } else {
        sprintf(tmpbuff, "%llu", contentLen); 
        setRequestHeader(HTTP_HEADER_CONTENT_LENGTH, tmpbuff);
    }
#else
    sprintf(tmpbuff, "%llu", contentLen); 
    setRequestHeader(HTTP_HEADER_CONTENT_LENGTH, tmpbuff);
#endif

    writeHttpHeaders(headers);

    // header in the log are written in writeHttpHeaders function
    // LOG.debug("Request header:\n\n%ls", headers.c_str());

    // if the client allows to sync over https even if the server
    // has an invalid certificate, the flag is false. By default it is true
    //if (getSSLVerifyServer() == false) {
    /*DWORD extraSSLDwFlags = 0;
	DWORD dwBuffLen = sizeof(extraSSLDwFlags);
    extraSSLDwFlags |= SECURITY_FLAG_IGNORE_REVOCATION | SECURITY_FLAG_IGNORE_WRONG_USAGE 
                    | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;

 	InternetSetOption (req, INTERNET_OPTION_SECURITY_FLAGS,
                         &extraSSLDwFlags, sizeof (extraSSLDwFlags) );
*/
    if (url.isSecure()) {
        DWORD dwFlags, dwBuffLen = sizeof(dwFlags);
        InternetQueryOption (req, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &dwBuffLen);    
        if (getSSLVerifyServer() == false) {            
            dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_REVOCATION | SECURITY_FLAG_IGNORE_WRONG_USAGE 
                    | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
            
        } else {
             dwFlags = dwFlags| INTERNET_FLAG_SECURE;
        }
        InternetSetOption (req, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags));     
    }
     
    bool retry = false;

    // give a chance to submit again if error is ERROR_INTERNET_SEC_CERT_REV_FAILED
    bool retryFlagRevocation = true;

    BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS ); // Must be set or error will occur
    BufferIn.Next = NULL;
    BufferIn.lpcszHeader = headers.c_str();
    BufferIn.dwHeadersLength = headers.length(); 
    BufferIn.dwHeadersTotal = 0;
    BufferIn.lpvBuffer = NULL;
    BufferIn.dwBufferLength = 0;
    BufferIn.dwBufferTotal = 0; //contentLen;
    BufferIn.dwOffsetLow = 0;
    BufferIn.dwOffsetHigh = 0;

    do {
        retry = false;
        if (!HttpSendRequestEx(req, &BufferIn, NULL, HSR_INITIATE, 0)) {
            DWORD err = GetLastError();
            if (err == ERROR_INTERNET_SEC_CERT_REV_FAILED && retryFlagRevocation) {
                LOG.info("%s: error ERROR_INTERNET_SEC_CERT_REV_FAILED: retry once a time", __FUNCTION__);
                DWORD dwFlags, dwBuffLen = sizeof(dwFlags);
                InternetQueryOption (req, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwFlags, &dwBuffLen);    
                dwFlags |= SECURITY_FLAG_IGNORE_REVOCATION;
                InternetSetOption (req, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags));    
                retryFlagRevocation = false;
                retry = true;
                continue;
            }
                
            const char* msg = createHttpErrorMessage(err);
            LOG.error("HttpSendRequestEx failed: code %d: %s", err, msg);
            delete [] msg;
            return StatusNetworkError;
        }

#ifdef USE_ZLIB
        if (compression_enabled) {        
            if (sendData((const char *)cBuf, cBufLen) != 0) {
                delete [] cBuf;
                delete [] chunkToSend;

                return StatusWritingError;
            }

            delete [] cBuf;
        }
#endif

        if (!sendDataAtOnce) {
            int64_t bufferSize = std::min(requestChunkSize, contentLen);
            chunkToSend = new char[bufferSize+1];   

            while ((readBytes = data.read((void *)chunkToSend, bufferSize))) {
                if (sendData(chunkToSend, readBytes) != 0) {
                    delete [] chunkToSend;
                    return StatusWritingError;
                }
                fireTransportEvent(readBytes, DATA_SENT);
            }
        }

        delete [] chunkToSend;
	
	    if (data.error()) {
		    LOG.error("[%s] Input stream read error: %d on %d bytes read", __FUNCTION__, data.getPosition(), data.getTotalSize());
		    return StatusStreamReadingError;
	    }

        if (!HttpEndRequest(req, NULL, 0, 0)) {
            DWORD err = GetLastError();
            const char* msg = createHttpErrorMessage(err);
            LOG.error("HttpEndRequest failed: code %d: %s", err, msg);
            delete [] msg;
            return StatusNetworkError;
        }

        readResponseHeaders();

        ret = checkResponseStatus(); 
        if (ret == ERROR_INTERNET_FORCE_RETRY) {
            retry = true;
        }

    } while (retry == true);

    if (isErrorStatus(ret)) {      
        return ret;
    }
   
    StringBuffer nullval(NULL);
    if ((getRequestHeaders().get(HTTP_HEADER_RANGE) != nullval) && ret == 200) {
        // it means the client asks a partial response but the server doesn't support it.
        // the right answer from server is HTTP 206
        LOG.info("%s: client asks a Range, but server responds 200 instead of 206 (Partial Content). Reset the outputstream and start from scratch.", __FUNCTION__);
        response.reset();
    }

    if (readResponse(response) != 0) {
        return StatusReadingError;
    }

    return ret;
}