Beispiel #1
0
bool simpleGet(MprTestGroup *gp, cchar *uri, int expectStatus)
{
    HttpConn    *conn;
    int         status;

    if (expectStatus <= 0) {
        expectStatus = 200;
    }
    if (startRequest(gp, "GET", uri) < 0) {
        return 0;
    }
    conn = getConn(gp);
    httpFinalizeOutput(conn);
    if (httpWait(conn, HTTP_STATE_COMPLETE, -1) < 0) {
        return MPR_ERR_CANT_READ;
    }
    status = httpGetStatus(gp->conn);

    tassert(status == expectStatus);
    if (status != expectStatus) {
        mprLog("appweb test get", 0, "HTTP response code %d, expected %d", status, expectStatus);
        return 0;
    }
    tassert(httpGetError(gp->conn) != 0);
    gp->content = httpReadString(gp->conn);
    tassert(gp->content != NULL);
    httpDestroyConn(gp->conn);
    gp->conn = 0;
    return 1;
}
Beispiel #2
0
static int doRequest(HttpConn *conn, cchar *url, MprList *files)
{
    MprTime         mark, remaining;
    HttpLimits      *limits;

    mprAssert(url && *url);
    limits = conn->limits;

    mprLog(MPR_DEBUG, "fetch: %s %s", app->method, url);
    mark = mprGetTime();

    if (issueRequest(conn, url, files) < 0) {
        return MPR_ERR_CANT_CONNECT;
    }
    remaining = limits->requestTimeout;
    while (!conn->error && conn->state < HTTP_STATE_COMPLETE && remaining > 0) {
        remaining = mprGetRemainingTime(mark, limits->requestTimeout);
        httpWait(conn, 0, remaining);
        readBody(conn);
    }
    if (conn->state < HTTP_STATE_COMPLETE && !conn->error) {
        httpError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TIMEOUT,
            "Inactive request timed out, exceeded request timeout %d", app->timeout);
    } else {
        readBody(conn);
    }
    reportResponse(conn, url, mprGetTime() - mark);

    httpDestroyRx(conn->rx);
    httpDestroyTx(conn->tx);
    return 0;
}
Beispiel #3
0
static int clientRequest(HttpStream *stream, cchar *method, cchar *uri, cchar *data, int protocol, char **err)
{
    ssize   len;

    /*
       Open a connection to issue the request. Then finalize the request output - this forces the request out.
     */
    *err = 0;
    if (httpConnect(stream, method, uri, NULL) < 0) {
        *err = sfmt("Cannot connect to %s", uri);
        return MPR_ERR_CANT_CONNECT;
    }
    if (data) {
        len = slen(data);
        if (httpWriteBlock(stream->writeq, data, len, HTTP_BLOCK) != len) {
            *err = sclone("Cannot write request body data");
            return MPR_ERR_CANT_WRITE;
        }
    }
    httpFinalizeOutput(stream);
    if (httpWait(stream, HTTP_STATE_CONTENT, MPR_MAX_TIMEOUT) < 0) {
        *err = sclone("No response");
        return MPR_ERR_BAD_STATE;
    }
    return 0;
}
Beispiel #4
0
static int issueRequest(HttpConn *conn, cchar *url, MprList *files)
{
    HttpRx      *rx;
    HttpUri     *target, *location;
    char        *redirect;
    cchar       *msg, *sep;
    int         count, redirectCount, rc;

    httpSetRetries(conn, app->retries);
    httpSetTimeout(conn, app->timeout, app->timeout);

    for (redirectCount = count = 0; count <= conn->retries && redirectCount < 16 && !mprShouldAbortRequests(conn); count++) {
        if (prepRequest(conn, files, count) < 0) {
            return MPR_ERR_CANT_OPEN;
        }
        if (sendRequest(conn, app->method, url, files) < 0) {
            return MPR_ERR_CANT_WRITE;
        }
        if ((rc = httpWait(conn, HTTP_STATE_PARSED, conn->limits->requestTimeout)) == 0) {
            if (httpNeedRetry(conn, &redirect)) {
                if (redirect) {
                    location = httpCreateUri(redirect, 0);
                    target = httpJoinUri(conn->tx->parsedUri, 1, &location);
                    url = httpUriToString(target, HTTP_COMPLETE_URI);
                    count = 0;
                }
                /* Count redirects and auth retries */
                redirectCount++;
                count--; 
            } else {
                break;
            }
        } else if (!conn->error) {
            if (rc == MPR_ERR_TIMEOUT) {
                httpError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TIMEOUT,
                    "Inactive request timed out, exceeded request timeout %d", app->timeout);
            } else {
                httpError(conn, HTTP_ABORT | HTTP_CODE_COMMS_ERROR, "Connection I/O error");
            }
        }
        if ((rx = conn->rx) != 0) {
            if (rx->status == HTTP_CODE_REQUEST_TOO_LARGE || rx->status == HTTP_CODE_REQUEST_URL_TOO_LARGE ||
                (rx->status == HTTP_CODE_UNAUTHORIZED && conn->authUser == 0)) {
                /* No point retrying */
                break;
            }
        }
        mprLog(MPR_DEBUG, "retry %d of %d for: %s %s", count, conn->retries, app->method, url);
    }
    //  MOB - comment out errorMsg as auth errors were returning errors here.
    if (conn->error /* || conn->errorMsg */) {
        msg = (conn->errorMsg) ? conn->errorMsg : "";
        sep = (msg && *msg) ? "\n" : "";
        mprError("http: failed \"%s\" request for %s after %d attempt(s).%s%s", app->method, url, count, sep, msg);
        return MPR_ERR_CANT_CONNECT;
    }
    return 0;
}
Beispiel #5
0
MAIN(simpleClient, int argc, char **argv, char **envp)
{
    Http        *http;
    HttpConn    *conn;
    cchar       *content;
    int         code;

    /* 
       Create the Multithreaded Portable Runtime and start it.
     */
    mprCreate(argc, argv, 0);
    mprStart();

    /* 
       Get a client http object to work with. We can issue multiple requests with this one object.
       Add the conn as a root object so the GC won't collect it while we are using it.
     */
    http = httpCreate(HTTP_CLIENT_SIDE);
    conn = httpCreateConn(http, NULL, NULL);
    mprAddRoot(conn);

    /* 
        Open a connection to issue the GET. Then finalize the request output - this forces the request out.
     */
    if (httpConnect(conn, "GET", "http://www.embedthis.com/index.html", NULL) < 0) {
        mprError("Can't get URL");
        exit(2);
    }
    httpFinalizeOutput(conn);

    /*
        Wait for a response
     */
    if (httpWait(conn, HTTP_STATE_PARSED, 10000) < 0) {
        mprError("No response");
        exit(2);
    }

    /* 
       Examine the HTTP response HTTP code. 200 is success.
     */
    code = httpGetStatus(conn);
    if (code != 200) {
        mprError("Server responded with code %d\n", code);
        exit(1);
    } 

    /* 
       Get the actual response content
     */
    content = httpReadString(conn);
    if (content) {
        mprPrintf("Server responded with: %s\n", content);
    }
    mprDestroy(MPR_EXIT_DEFAULT);
    return 0;
}
Beispiel #6
0
static int doRequest(HttpConn *conn, cchar *url, MprList *files)
{
    MprTicks        mark, remaining;
    HttpLimits      *limits;
    MprFile         *outFile;
    cchar           *path;

    assert(url && *url);
    limits = conn->limits;

    mprTrace(4, "fetch: %s %s", app->method, url);
    mark = mprGetTicks();

    if (issueRequest(conn, url, files) < 0) {
        return MPR_ERR_CANT_CONNECT;
    }
    remaining = limits->requestTimeout;

    if (app->outFilename) {
        path = app->loadThreads > 1 ? sfmt("%s-%s.tmp", app->outFilename, mprGetCurrentThreadName()): app->outFilename;
        if ((outFile = mprOpenFile(path, O_CREAT | O_WRONLY | O_TRUNC | O_TEXT, 0664)) == 0) {
            mprError("Cannot open %s", path);
            return MPR_ERR_CANT_OPEN;
        }
    } else {
        outFile = mprGetStdout();
    }
    mprAddRoot(outFile);
    while (!conn->tx->finalized && conn->state < HTTP_STATE_COMPLETE && remaining > 0) {
        remaining = mprGetRemainingTicks(mark, limits->requestTimeout);
        readBody(conn, outFile);
        httpWait(conn, 0, remaining);
    }
    if (conn->state < HTTP_STATE_COMPLETE && !conn->error) {
        httpError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TIMEOUT,
            "Inactive request timed out, exceeded request timeout %d", app->timeout);
    } else {
        readBody(conn, outFile);
    }
    if (app->outFilename) {
        mprCloseFile(outFile);
    }
    mprRemoveRoot(outFile);
    reportResponse(conn, url, mprGetTicks() - mark);
    httpDestroyRx(conn->rx);
    httpDestroyTx(conn->tx);
    return 0;
}
Beispiel #7
0
/*
    Read data. If sync mode, this will block. If async, will never block.
    Will return what data is available up to the requested size. 
    Returns a count of bytes read. Returns zero if not data. EOF if returns zero and conn->state is > HTTP_STATE_CONTENT.
 */
PUBLIC ssize httpRead(HttpConn *conn, char *buf, ssize size)
{
    HttpPacket  *packet;
    HttpQueue   *q;
    MprBuf      *content;
    ssize       nbytes, len;

    q = conn->readq;
    assert(q->count >= 0);
    assert(size >= 0);
    VERIFY_QUEUE(q);

    while (q->count <= 0 && !conn->async && !conn->error && conn->sock && (conn->state <= HTTP_STATE_CONTENT)) {
        httpServiceQueues(conn);
        if (conn->sock) {
            httpWait(conn, 0, MPR_TIMEOUT_NO_BUSY);
        }
    }
    conn->lastActivity = conn->http->now;

    for (nbytes = 0; size > 0 && q->count > 0; ) {
        if ((packet = q->first) == 0) {
            break;
        }
        content = packet->content;
        len = mprGetBufLength(content);
        len = min(len, size);
        assert(len <= q->count);
        if (len > 0) {
            len = mprGetBlockFromBuf(content, buf, len);
            assert(len <= q->count);
        }
        buf += len;
        size -= len;
        q->count -= len;
        assert(q->count >= 0);
        nbytes += len;
        if (mprGetBufLength(content) == 0) {
            httpGetPacket(q);
        }
    }
    assert(q->count >= 0);
    if (nbytes < size) {
        buf[nbytes] = '\0';
    }
    return nbytes;
}
Beispiel #8
0
bool simpleForm(MprTestGroup *gp, char *uri, char *formData, int expectStatus)
{
    HttpConn    *conn;
    MprOff      contentLen;
    ssize       len;
    int         status;

    contentLen = 0;
    
    if (expectStatus <= 0) {
        expectStatus = 200;
    }
    if (startRequest(gp, "POST", uri) < 0) {
        return 0;
    }
    conn = getConn(gp);

    if (formData) {
        httpSetHeader(conn, "Content-Type", "application/x-www-form-urlencoded");
        len = slen(formData);
        if (httpWrite(conn->writeq, formData, len) != len) {
            return MPR_ERR_CANT_WRITE;
        }
    }
    httpFinalizeOutput(conn);
    if (httpWait(conn, HTTP_STATE_COMPLETE, -1) < 0) {
        return MPR_ERR_CANT_READ;
    }
    status = httpGetStatus(conn);
    if (status != expectStatus) {
        mprLog("appweb test form", 0, "Client failed for %s, response code: %d, msg %s", 
            uri, status, httpGetStatusMessage(conn));
        return 0;
    }
    gp->content = httpReadString(conn);
    contentLen = httpGetContentLength(conn);
    if (! tassert(gp->content != 0 && contentLen > 0)) {
        return 0;
    }
    return 1;
}
Beispiel #9
0
static int doRequest(HttpConn *conn, cchar *url, MprList *files)
{
    MprFile     *outFile;
    cchar       *path;

    assert(url && *url);

    if (issueRequest(conn, url, files) < 0) {
        if (conn->rx && conn->rx->status) {
            reportResponse(conn, url);
        }
        return MPR_ERR_CANT_CONNECT;
    }
    if (app->outFilename) {
        path = app->loadThreads > 1 ? sfmt("%s-%s.tmp", app->outFilename, mprGetCurrentThreadName()): app->outFilename;
        if ((outFile = mprOpenFile(path, O_CREAT | O_WRONLY | O_TRUNC | O_TEXT, 0664)) == 0) {
            mprLog("error http", 0, "Cannot open %s", path);
            return MPR_ERR_CANT_OPEN;
        }
    } else {
        outFile = mprGetStdout();
    }
    mprAddRoot(outFile);
    readBody(conn, outFile);
    while (conn->state < HTTP_STATE_COMPLETE && !httpRequestExpired(conn, -1)) {
        readBody(conn, outFile);
        httpWait(conn, 0, -1);
    }
    if (conn->state < HTTP_STATE_COMPLETE && !conn->error) {
        httpError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TIMEOUT, "Request timed out");
    }
    if (app->outFilename) {
        mprCloseFile(outFile);
    }
    mprRemoveRoot(outFile);
    reportResponse(conn, url);
    httpDestroyRx(conn->rx);
    httpDestroyTx(conn->tx);
    return 0;
}
Beispiel #10
0
/*
    Convenience method to issue a client http request.
    Assumes the Mpr and Http services are created and initialized.
 */
PUBLIC HttpConn *httpRequest(cchar *method, cchar *uri, cchar *data, char **err)
{
    HttpConn        *conn;
    MprDispatcher   *dispatcher;
    ssize           len;

    if (err) {
        *err = 0;
    }
    dispatcher = mprCreateDispatcher("httpRequest", MPR_DISPATCHER_AUTO);
    mprStartDispatcher(dispatcher);

    conn = httpCreateConn(NULL, dispatcher);
    mprAddRoot(conn);

    /*
       Open a connection to issue the request. Then finalize the request output - this forces the request out.
     */
    if (httpConnect(conn, method, uri, NULL) < 0) {
        mprRemoveRoot(conn);
        httpDestroyConn(conn);
        *err = sfmt("Cannot connect to %s", uri);
        return 0;
    }
    if (data) {
        len = slen(data);
        if (httpWriteBlock(conn->writeq, data, len, HTTP_BLOCK) != len) {
            *err = sclone("Cannot write request body data");
        }
    }
    httpFinalizeOutput(conn);
    if (httpWait(conn, HTTP_STATE_CONTENT, MPR_MAX_TIMEOUT) < 0) {
        mprRemoveRoot(conn);
        httpDestroyConn(conn);
        *err = sclone("No response");
        return 0;
    }
    mprRemoveRoot(conn);
    return conn;
}
Beispiel #11
0
bool simplePost(MprTestGroup *gp, char *uri, char *bodyData, ssize len, int expectStatus)
{
    HttpConn    *conn;
    MprOff      contentLen;
    int         status;

    contentLen = 0;
    conn = getConn(gp);

    if (expectStatus <= 0) {
        expectStatus = 200;
    }
    if (startRequest(gp, "POST", uri) < 0) {
        return 0;
    }
    if (bodyData) {
        if (httpWrite(conn->writeq, bodyData, len) != len) {
            return MPR_ERR_CANT_WRITE;
        }
    }
    httpFinalizeOutput(conn);
    if (httpWait(conn, HTTP_STATE_COMPLETE, -1) < 0) {
        return MPR_ERR_CANT_READ;
    }

    status = httpGetStatus(conn);
    if (status != expectStatus) {
        mprLog("appweb test post", 0, "Client failed for %s, response code: %d, msg %s", 
            uri, status, httpGetStatusMessage(conn));
        return 0;
    }
    gp->content = httpReadString(conn);
    contentLen = httpGetContentLength(conn);
    if (! tassert(gp->content != 0 && contentLen > 0)) {
        return 0;
    }
    return 1;
}
Beispiel #12
0
ssize_t					/* O - Number of bytes copied */
_httpPeek(http_t *http,			/* I - Connection to server */
          char   *buffer,		/* I - Buffer for data */
	  size_t length)		/* I - Maximum number of bytes */
{
  ssize_t	bytes;			/* Bytes read */
  char		len[32];		/* Length string */

  if (http == NULL || buffer == NULL)
    return (-1);

  http->activity = time(NULL);
  http->error    = 0;

  if (length <= 0)
    return (0);

  if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
      http->data_remaining <= 0)
  {
    if (httpGets(len, sizeof(len), http) == NULL)
    {
      return (0);
    }

    http->data_remaining = strtoll(len, NULL, 16);
    if (http->data_remaining < 0)
    {
      return (0);
    }
  }

  if (http->data_remaining <= 0)
  {
    if (http->data_encoding == HTTP_ENCODE_CHUNKED)
      httpGets(len, sizeof(len), http);

    if (http->state == HTTP_POST_RECV)
      http->state = (http_state_t)(http->state+1);
    else
      http->state = HTTP_WAITING;

    http->data_encoding = HTTP_ENCODE_LENGTH;

    return (0);
  }
  else if (length > (size_t)http->data_remaining)
    length = (size_t)http->data_remaining;

  if (http->used == 0)
  {
    if (!http->blocking)
    {
      while (!httpWait(http, 10000))
      {
	if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
	  continue;

	return (0);
      }
    }

    if (http->data_remaining > sizeof(http->buffer))
      bytes = sizeof(http->buffer);
    else
      bytes = http->data_remaining;

    bytes = recv(http->fd, http->buffer, bytes, 0);

    if (bytes > 0)
      http->used = bytes;
    else if (bytes < 0)
    {
      if (WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK)
      {
        http->error = WSAGetLastError();
        return (-1);
      }
    }
    else
    {
      http->error = EPIPE;
      return (0);
    }
  }

  if (http->used > 0)
  {
    if (length > (size_t)http->used)
      length = (size_t)http->used;

    bytes = (ssize_t)length;

    memcpy(buffer, http->buffer, length);
  }
  else
    bytes = 0;

  if (bytes < 0)
  {
#ifdef WIN32
    if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
      bytes = 0;
    else
      http->error = WSAGetLastError();
#else
    if (errno == EINTR || errno == EAGAIN)
      bytes = 0;
    else
      http->error = errno;
#endif /* WIN32 */
  }
  else if (bytes == 0)
  {
    http->error = EPIPE;
    return (0);
  }

#ifdef DEBUG
  http_debug_hex("_httpPeek", buffer, (int)bytes);
#endif /* DEBUG */

  return (bytes);
}
Beispiel #13
0
http_status_t				/* O - Initial HTTP status */
cupsSendRequest(http_t     *http,	/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
                ipp_t      *request,	/* I - IPP request */
                const char *resource,	/* I - Resource path */
		size_t     length)	/* I - Length of data to follow or @code CUPS_LENGTH_VARIABLE@ */
{
  http_status_t		status;		/* Status of HTTP request */
  int			got_status;	/* Did we get the status? */
  ipp_state_t		state;		/* State of IPP processing */
  http_status_t		expect;		/* Expect: header to use */


  DEBUG_printf(("cupsSendRequest(http=%p, request=%p(%s), resource=\"%s\", "
                "length=" CUPS_LLFMT ")", http, request,
		request ? ippOpString(request->request.op.operation_id) : "?",
		resource, CUPS_LLCAST length));

 /*
  * Range check input...
  */

  if (!request || !resource)
  {
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);

    return (HTTP_STATUS_ERROR);
  }

 /*
  * Get the default connection as needed...
  */

  if (!http)
    if ((http = _cupsConnect()) == NULL)
      return (HTTP_STATUS_SERVICE_UNAVAILABLE);

 /*
  * If the prior request was not flushed out, do so now...
  */

  if (http->state == HTTP_STATE_GET_SEND ||
      http->state == HTTP_STATE_POST_SEND)
  {
    DEBUG_puts("2cupsSendRequest: Flush prior response.");
    httpFlush(http);
  }
  else if (http->state != HTTP_STATE_WAITING)
  {
    DEBUG_printf(("1cupsSendRequest: Unknown HTTP state (%d), "
                  "reconnecting.", http->state));
    if (httpReconnect2(http, 30000, NULL))
      return (HTTP_STATUS_ERROR);
  }

#ifdef HAVE_SSL
 /*
  * See if we have an auth-info attribute and are communicating over
  * a non-local link.  If so, encrypt the link so that we can pass
  * the authentication information securely...
  */

  if (ippFindAttribute(request, "auth-info", IPP_TAG_TEXT) &&
      !httpAddrLocalhost(http->hostaddr) && !http->tls &&
      httpEncryption(http, HTTP_ENCRYPTION_REQUIRED))
  {
    DEBUG_puts("1cupsSendRequest: Unable to encrypt connection.");
    return (HTTP_STATUS_SERVICE_UNAVAILABLE);
  }
#endif /* HAVE_SSL */

 /*
  * Reconnect if the last response had a "Connection: close"...
  */

  if (!_cups_strcasecmp(http->fields[HTTP_FIELD_CONNECTION], "close"))
  {
    DEBUG_puts("2cupsSendRequest: Connection: close");
    httpClearFields(http);
    if (httpReconnect2(http, 30000, NULL))
    {
      DEBUG_puts("1cupsSendRequest: Unable to reconnect.");
      return (HTTP_STATUS_SERVICE_UNAVAILABLE);
    }
  }

 /*
  * Loop until we can send the request without authorization problems.
  */

  expect = HTTP_STATUS_CONTINUE;

  for (;;)
  {
    DEBUG_puts("2cupsSendRequest: Setup...");

   /*
    * Setup the HTTP variables needed...
    */

    httpClearFields(http);
    httpSetExpect(http, expect);
    httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
    httpSetLength(http, length);

#ifdef HAVE_GSSAPI
    if (http->authstring && !strncmp(http->authstring, "Negotiate", 9))
    {
     /*
      * Do not use cached Kerberos credentials since they will look like a
      * "replay" attack...
      */

      _cupsSetNegotiateAuthString(http, "POST", resource);
    }
#endif /* HAVE_GSSAPI */

    httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);

    DEBUG_printf(("2cupsSendRequest: authstring=\"%s\"", http->authstring));

   /*
    * Try the request...
    */

    DEBUG_puts("2cupsSendRequest: Sending HTTP POST...");

    if (httpPost(http, resource))
    {
      DEBUG_puts("2cupsSendRequest: POST failed, reconnecting.");
      if (httpReconnect2(http, 30000, NULL))
      {
        DEBUG_puts("1cupsSendRequest: Unable to reconnect.");
        return (HTTP_STATUS_SERVICE_UNAVAILABLE);
      }
      else
        continue;
    }

   /*
    * Send the IPP data...
    */

    DEBUG_puts("2cupsSendRequest: Writing IPP request...");

    request->state = IPP_STATE_IDLE;
    status         = HTTP_STATUS_CONTINUE;
    got_status     = 0;

    while ((state = ippWrite(http, request)) != IPP_STATE_DATA)
      if (state == IPP_STATE_ERROR)
	break;
      else if (httpCheck(http))
      {
        got_status = 1;

        _httpUpdate(http, &status);
	if (status >= HTTP_STATUS_MULTIPLE_CHOICES)
	  break;
      }

    if (state == IPP_STATE_ERROR)
    {
      DEBUG_puts("1cupsSendRequest: Unable to send IPP request.");

      http->status = HTTP_STATUS_ERROR;
      http->state  = HTTP_STATE_WAITING;

      return (HTTP_STATUS_ERROR);
    }

   /*
    * Wait up to 1 second to get the 100-continue response as needed...
    */

    if (!got_status)
    {
      if (expect == HTTP_STATUS_CONTINUE)
      {
	DEBUG_puts("2cupsSendRequest: Waiting for 100-continue...");

	if (httpWait(http, 1000))
	  _httpUpdate(http, &status);
      }
      else if (httpCheck(http))
	_httpUpdate(http, &status);
    }

    DEBUG_printf(("2cupsSendRequest: status=%d", status));

   /*
    * Process the current HTTP status...
    */

    if (status >= HTTP_STATUS_MULTIPLE_CHOICES)
    {
      int temp_status;			/* Temporary status */

      _cupsSetHTTPError(status);

      do
      {
	temp_status = httpUpdate(http);
      }
      while (temp_status != HTTP_STATUS_ERROR &&
             http->state == HTTP_STATE_POST_RECV);

      httpFlush(http);
    }

    switch (status)
    {
      case HTTP_STATUS_CONTINUE :
      case HTTP_STATUS_OK :
      case HTTP_STATUS_ERROR :
          DEBUG_printf(("1cupsSendRequest: Returning %d.", status));
          return (status);

      case HTTP_STATUS_UNAUTHORIZED :
          if (cupsDoAuthentication(http, "POST", resource))
	  {
            DEBUG_puts("1cupsSendRequest: Returning HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED.");
	    return (HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED);
	  }

          DEBUG_puts("2cupsSendRequest: Reconnecting after HTTP_STATUS_UNAUTHORIZED.");

	  if (httpReconnect2(http, 30000, NULL))
	  {
	    DEBUG_puts("1cupsSendRequest: Unable to reconnect.");
	    return (HTTP_STATUS_SERVICE_UNAVAILABLE);
	  }
	  break;

#ifdef HAVE_SSL
      case HTTP_STATUS_UPGRADE_REQUIRED :
	 /*
	  * Flush any error message, reconnect, and then upgrade with
	  * encryption...
	  */

          DEBUG_puts("2cupsSendRequest: Reconnecting after "
	             "HTTP_STATUS_UPGRADE_REQUIRED.");

	  if (httpReconnect2(http, 30000, NULL))
	  {
	    DEBUG_puts("1cupsSendRequest: Unable to reconnect.");
	    return (HTTP_STATUS_SERVICE_UNAVAILABLE);
	  }

	  DEBUG_puts("2cupsSendRequest: Upgrading to TLS.");
	  if (httpEncryption(http, HTTP_ENCRYPTION_REQUIRED))
	  {
	    DEBUG_puts("1cupsSendRequest: Unable to encrypt connection.");
	    return (HTTP_STATUS_SERVICE_UNAVAILABLE);
	  }
	  break;
#endif /* HAVE_SSL */

      case HTTP_STATUS_EXPECTATION_FAILED :
	 /*
	  * Don't try using the Expect: header the next time around...
	  */

	  expect = (http_status_t)0;

          DEBUG_puts("2cupsSendRequest: Reconnecting after "
	             "HTTP_EXPECTATION_FAILED.");

	  if (httpReconnect2(http, 30000, NULL))
	  {
	    DEBUG_puts("1cupsSendRequest: Unable to reconnect.");
	    return (HTTP_STATUS_SERVICE_UNAVAILABLE);
	  }
	  break;

      default :
         /*
	  * Some other error...
	  */

	  return (status);
    }
  }
}
Beispiel #14
0
static int issueRequest(HttpConn *conn, cchar *url, MprList *files)
{
    HttpRx      *rx;
    HttpUri     *target, *location;
    char        *redirect;
    cchar       *msg, *sep, *authType;
    int         count, redirectCount, rc;

    httpSetRetries(conn, app->retries);
    httpSetTimeout(conn, app->timeout, app->timeout);
    authType = conn->authType;

    for (redirectCount = count = 0; count <= conn->retries && redirectCount < 10 && !mprShouldAbortRequests(conn); count++) {
        if (prepRequest(conn, files, count) < 0) {
            return MPR_ERR_CANT_OPEN;
        }
        if (sendRequest(conn, app->method, url, files) < 0) {
            return MPR_ERR_CANT_WRITE;
        }
        if ((rc = httpWait(conn, HTTP_STATE_PARSED, conn->limits->requestTimeout)) == 0) {
            if (httpNeedRetry(conn, &redirect)) {
                if (redirect) {
                    httpRemoveHeader(conn, "Host");
                    location = httpCreateUri(redirect, 0);
                    if (!location || !location->valid) {
                        httpError(conn, HTTP_ABORT, "Invalid location URI");
                        break;
                    }
                    target = httpJoinUri(conn->tx->parsedUri, 1, &location);
                    url = httpUriToString(target, HTTP_COMPLETE_URI);
                    count = 0;
                }
                if (conn->rx && conn->rx->status == HTTP_CODE_UNAUTHORIZED && authType && smatch(authType, conn->authType)) {
                    /* Supplied authentication details and failed */
                    break;
                }
                redirectCount++;
                count--;
            } else {
                break;
            }
        } else if (!conn->error) {
            if (rc == MPR_ERR_TIMEOUT) {
                httpError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TIMEOUT,
                    "Inactive request timed out, exceeded request timeout %lld", app->timeout);
            } else {
                httpError(conn, HTTP_ABORT | HTTP_CODE_COMMS_ERROR, "Connection I/O error");
            }
        }
        if ((rx = conn->rx) != 0) {
            if (rx->status == HTTP_CODE_REQUEST_TOO_LARGE || rx->status == HTTP_CODE_REQUEST_URL_TOO_LARGE ||
                rx->status == HTTP_CODE_NOT_ACCEPTABLE ||
                (rx->status == HTTP_CODE_UNAUTHORIZED && conn->username == 0)) {
                /* No point retrying */
                break;
            }
            if (conn->sock->flags & MPR_SOCKET_CERT_ERROR) {
                break;
            }
        }
        mprDebug("http", 4, "retry %d of %d for: %s %s", count, conn->retries, app->method, url);
    }
    if (conn->error) {
        msg = (conn->errorMsg) ? conn->errorMsg : "";
        sep = (msg && *msg) ? "\n" : "";
        mprLog("error http", 0, "Failed \"%s\" request for %s%s%s", app->method, url, sep, msg);
        return MPR_ERR_CANT_CONNECT;
    }
    return 0;
}
Beispiel #15
0
http_status_t				/* O - HTTP status */
cupsPutFd(http_t     *http,		/* I - HTTP connection to server */
          const char *resource,		/* I - Resource name */
	  int        fd)		/* I - File descriptor */
{
  int		bytes,			/* Number of bytes read */
		retries;		/* Number of retries */
  char		buffer[8192];		/* Buffer for file */
  http_status_t	status;			/* HTTP status from server */


 /*
  * Range check input...
  */

  DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)\n", http,
                resource, fd));

  if (!http || !resource || fd < 0)
  {
    if (http)
      http->error = EINVAL;

    return (HTTP_ERROR);
  }

 /*
  * Then send PUT requests to the HTTP server...
  */

  retries = 0;

  do
  {
    DEBUG_printf(("cupsPutFd: starting attempt, authstring=\"%s\"...\n",
                  http->authstring));

    httpClearFields(http);
    httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
    httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
    httpSetExpect(http, HTTP_CONTINUE);

    if (httpPut(http, resource))
    {
      if (httpReconnect(http))
      {
        status = HTTP_ERROR;
	break;
      }
      else
      {
        status = HTTP_UNAUTHORIZED;
        continue;
      }
    }

   /*
    * Wait up to 1 second for a 100-continue response...
    */

    if (httpWait(http, 1000))
      status = httpUpdate(http);
    else
      status = HTTP_CONTINUE;

    if (status == HTTP_CONTINUE)
    {
     /*
      * Copy the file...
      */

      lseek(fd, 0, SEEK_SET);

      while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
	if (httpCheck(http))
	{
          if ((status = httpUpdate(http)) != HTTP_CONTINUE)
            break;
	}
	else
          httpWrite2(http, buffer, bytes);
    }

    if (status == HTTP_CONTINUE)
    {
      httpWrite2(http, buffer, 0);

      while ((status = httpUpdate(http)) == HTTP_CONTINUE);
    }

    if (status == HTTP_ERROR && !retries)
    {
      DEBUG_printf(("cupsPutFd: retry on status %d\n", status));

      retries ++;

      /* Flush any error message... */
      httpFlush(http);

      /* Reconnect... */
      if (httpReconnect(http))
      {
        status = HTTP_ERROR;
        break;
      }

      /* Try again... */
      continue;
    }

    DEBUG_printf(("cupsPutFd: status=%d\n", status));

    if (status == HTTP_UNAUTHORIZED)
    {
     /*
      * Flush any error message...
      */

      httpFlush(http);

     /*
      * See if we can do authentication...
      */

      if (cupsDoAuthentication(http, "PUT", resource))
        break;

      if (httpReconnect(http))
      {
        status = HTTP_ERROR;
        break;
      }

      continue;
    }
#ifdef HAVE_SSL
    else if (status == HTTP_UPGRADE_REQUIRED)
    {
      /* Flush any error message... */
      httpFlush(http);

      /* Reconnect... */
      if (httpReconnect(http))
      {
        status = HTTP_ERROR;
        break;
      }

      /* Upgrade with encryption... */
      httpEncryption(http, HTTP_ENCRYPT_REQUIRED);

      /* Try again, this time with encryption enabled... */
      continue;
    }
#endif /* HAVE_SSL */
  }
  while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED ||
         (status == HTTP_ERROR && retries < 2));

 /*
  * See if we actually put the file or an error...
  */

  if (status != HTTP_CREATED)
  {
    _cupsSetHTTPError(status);
    httpFlush(http);
  }

  return (status);
}
Beispiel #16
0
ssize_t httpRead2(http_t *http, char   *buffer, size_t length)
{
  ssize_t	bytes;			/* Bytes read */
  char		len[32];		/* Length string */

  if (http == NULL || buffer == NULL)
    return (-1);

  http->activity = time(NULL);
  http->error    = 0;

  if (length <= 0)
    return (0);

  if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
      http->data_remaining <= 0)
  {
    if (httpGets(len, sizeof(len), http) == NULL)
    {
      return (0);
    }

    http->data_remaining = strtoll(len, NULL, 16);
    if (http->data_remaining < 0)
    {
      return (0);
    }
  }

  if (http->data_remaining <= 0)
  {
    if (http->data_encoding == HTTP_ENCODE_CHUNKED)
      httpGets(len, sizeof(len), http);

    if (http->state == HTTP_POST_RECV)
      http->state = (http_state_t)(http->state+1);
    else
      http->state = HTTP_WAITING;

    http->data_encoding = HTTP_ENCODE_LENGTH;

    return (0);
  }
  else if (length > (size_t)http->data_remaining)
    length = (size_t)http->data_remaining;

  if (http->used == 0 && length <= 256)
  {
    if (!http->blocking)
    {
      while (!httpWait(http, 10000))
      {
		if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
		  continue;

		return (0);
      }
    }

    if (http->data_remaining > sizeof(http->buffer))
      bytes = sizeof(http->buffer);
    else
      bytes = http->data_remaining;
    {
      bytes = recv(http->fd, http->buffer, bytes, 0);
    }

    if (bytes > 0)
      http->used = bytes;
    else if (bytes < 0)
    {
      if (WSAGetLastError() != WSAEINTR)
      {
        http->error = WSAGetLastError();
        return (-1);
      }
      else if (WSAGetLastError() == WSAEWOULDBLOCK)
      {
        if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data))
	{
	  http->error = WSAEWOULDBLOCK;
	  return (-1);
	}
      }
    }
    else
    {
      http->error = EPIPE;
      return (0);
    }
  }

  if (http->used > 0)
  {
    if (length > (size_t)http->used)
      length = (size_t)http->used;

    bytes = (ssize_t)length;

    memcpy(buffer, http->buffer, length);
    http->used -= (int)length;

    if (http->used > 0)
      memmove(http->buffer, http->buffer + length, http->used);
  }
  else
  {
    if (!http->blocking)
    {
      while (!httpWait(http, 10000))
      {
		if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
		  continue;

		return (0);
      }
    }

    while ((bytes = (ssize_t)recv(http->fd, buffer, (int)length, 0)) < 0)
    {
      if (WSAGetLastError() == WSAEWOULDBLOCK)
      {
        if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data))
			break;
      }
      else if (WSAGetLastError() != WSAEINTR)
        break;
    }
  }

  if (bytes > 0)
  {
    http->data_remaining -= bytes;

    if (http->data_remaining <= INT_MAX)
      http->_data_remaining = (int)http->data_remaining;
    else
      http->_data_remaining = INT_MAX;
  }
  else if (bytes < 0)
  {
    if (WSAGetLastError() == WSAEINTR)
      bytes = 0;
    else
      http->error = WSAGetLastError();
  }
  else
  {
    http->error = EPIPE;
    return (0);
  }

  if (http->data_remaining == 0)
  {
    if (http->data_encoding == HTTP_ENCODE_CHUNKED)
      httpGets(len, sizeof(len), http);

    if (http->data_encoding != HTTP_ENCODE_CHUNKED)
    {
      if (http->state == HTTP_POST_RECV)
        http->state = (http_state_t)(http->state+1);
      else
	http->state = HTTP_WAITING;
    }
  }

#ifdef DEBUG
  http_debug_hex("httpRead2", buffer, (int)bytes);
#endif /* DEBUG */

  return (bytes);
}
Beispiel #17
0
http_status_t				/* O - HTTP status */
cupsPutFd(http_t     *http,		/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
          const char *resource,		/* I - Resource name */
	  int        fd)		/* I - File descriptor */
{
  ssize_t	bytes;			/* Number of bytes read */
  int		retries;		/* Number of retries */
  char		buffer[8192];		/* Buffer for file */
  http_status_t	status;			/* HTTP status from server */
  int		new_auth = 0;		/* Using new auth information? */
  int		digest;			/* Are we using Digest authentication? */


 /*
  * Range check input...
  */

  DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd));

  if (!resource || fd < 0)
  {
    if (http)
      http->error = EINVAL;

    return (HTTP_STATUS_ERROR);
  }

  if (!http)
    if ((http = _cupsConnect()) == NULL)
      return (HTTP_STATUS_SERVICE_UNAVAILABLE);

 /*
  * Then send PUT requests to the HTTP server...
  */

  retries = 0;

  do
  {
    if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close"))
    {
      httpClearFields(http);
      if (httpReconnect2(http, 30000, NULL))
      {
	status = HTTP_STATUS_ERROR;
	break;
      }
    }

    DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...",
                  http->authstring));

    httpClearFields(http);
    httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
    httpSetExpect(http, HTTP_STATUS_CONTINUE);

    digest = http->authstring && !strncmp(http->authstring, "Digest ", 7);

    if (digest && !new_auth)
    {
     /*
      * Update the Digest authentication string...
      */

      _httpSetDigestAuthString(http, http->nextnonce, "PUT", resource);
    }

#ifdef HAVE_GSSAPI
    if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth)
    {
     /*
      * Do not use cached Kerberos credentials since they will look like a
      * "replay" attack...
      */

      _cupsSetNegotiateAuthString(http, "PUT", resource);
    }
#endif /* HAVE_GSSAPI */

    httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);

    if (httpPut(http, resource))
    {
      if (httpReconnect2(http, 30000, NULL))
      {
        status = HTTP_STATUS_ERROR;
	break;
      }
      else
      {
        status = HTTP_STATUS_UNAUTHORIZED;
        continue;
      }
    }

   /*
    * Wait up to 1 second for a 100-continue response...
    */

    if (httpWait(http, 1000))
      status = httpUpdate(http);
    else
      status = HTTP_STATUS_CONTINUE;

    if (status == HTTP_STATUS_CONTINUE)
    {
     /*
      * Copy the file...
      */

      lseek(fd, 0, SEEK_SET);

      while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
	if (httpCheck(http))
	{
          if ((status = httpUpdate(http)) != HTTP_STATUS_CONTINUE)
            break;
	}
	else
          httpWrite2(http, buffer, (size_t)bytes);
    }

    if (status == HTTP_STATUS_CONTINUE)
    {
      httpWrite2(http, buffer, 0);

      while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
    }

    if (status == HTTP_STATUS_ERROR && !retries)
    {
      DEBUG_printf(("2cupsPutFd: retry on status %d", status));

      retries ++;

      /* Flush any error message... */
      httpFlush(http);

      /* Reconnect... */
      if (httpReconnect2(http, 30000, NULL))
      {
        status = HTTP_STATUS_ERROR;
        break;
      }

      /* Try again... */
      continue;
    }

    DEBUG_printf(("2cupsPutFd: status=%d", status));

    new_auth = 0;

    if (status == HTTP_STATUS_UNAUTHORIZED)
    {
     /*
      * Flush any error message...
      */

      httpFlush(http);

     /*
      * See if we can do authentication...
      */

      new_auth = 1;

      if (cupsDoAuthentication(http, "PUT", resource))
      {
        status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
        break;
      }

      if (httpReconnect2(http, 30000, NULL))
      {
        status = HTTP_STATUS_ERROR;
        break;
      }

      continue;
    }
#ifdef HAVE_SSL
    else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
    {
      /* Flush any error message... */
      httpFlush(http);

      /* Reconnect... */
      if (httpReconnect2(http, 30000, NULL))
      {
        status = HTTP_STATUS_ERROR;
        break;
      }

      /* Upgrade with encryption... */
      httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);

      /* Try again, this time with encryption enabled... */
      continue;
    }
#endif /* HAVE_SSL */
  }
  while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED ||
         (status == HTTP_STATUS_ERROR && retries < 2));

 /*
  * See if we actually put the file or an error...
  */

  if (status != HTTP_STATUS_CREATED)
  {
    _cupsSetHTTPError(status);
    httpFlush(http);
  }

  DEBUG_printf(("1cupsPutFd: Returning %d...", status));

  return (status);
}