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; }
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; }
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; }
PUBLIC void httpFinalize(HttpConn *conn) { HttpTx *tx; tx = conn->tx; if (!tx || tx->finalized) { return; } tx->finalized = 1; if (!tx->finalizedOutput) { httpFinalizeOutput(conn); } else { httpServiceQueues(conn); } }
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; }
/* 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; }
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; }
static int sendRequest(HttpConn *conn, cchar *method, cchar *url, MprList *files) { if (httpConnect(conn, method, url, app->ssl) < 0) { mprError("Cannot process request for \"%s\"\n%s", url, httpGetError(conn)); return MPR_ERR_CANT_OPEN; } /* This program does not do full-duplex writes with reads. ie. if you have a request that sends and receives data in parallel -- http will do the writes first then read the response. */ if (app->bodyData || app->formData || files) { if (app->chunkSize > 0) { httpSetChunkSize(conn, app->chunkSize); } if (writeBody(conn, files) < 0) { mprError("Cannot write body data to \"%s\". %s", url, httpGetError(conn)); return MPR_ERR_CANT_WRITE; } } assert(!mprGetCurrentThread()->yielded); httpFinalizeOutput(conn); return 0; }
PUBLIC void httpStartPipeline(HttpConn *conn) { HttpQueue *qhead, *q, *prevQ, *nextQ; HttpTx *tx; HttpRx *rx; tx = conn->tx; rx = conn->rx; assert(conn->endpoint); if (rx->needInputPipeline) { qhead = tx->queue[HTTP_QUEUE_RX]; for (q = qhead->nextQ; !tx->finalized && q->nextQ != qhead; q = nextQ) { nextQ = q->nextQ; if (q->start && !(q->flags & HTTP_QUEUE_STARTED)) { if (q->pair == 0 || !(q->pair->flags & HTTP_QUEUE_STARTED)) { q->flags |= HTTP_QUEUE_STARTED; q->stage->start(q); } } } } qhead = tx->queue[HTTP_QUEUE_TX]; for (q = qhead->prevQ; !tx->finalized && q->prevQ != qhead; q = prevQ) { prevQ = q->prevQ; if (q->start && !(q->flags & HTTP_QUEUE_STARTED)) { q->flags |= HTTP_QUEUE_STARTED; q->stage->start(q); } } httpStartHandler(conn); if (tx->pendingFinalize) { tx->finalizedOutput = 0; httpFinalizeOutput(conn); } }
/* Wait for the connection to reach a given state. Should only be used on the client side. @param state Desired state. Set to zero if you want to wait for one I/O event. @param timeout Timeout in msec. If timeout is zero, wait forever. If timeout is < 0, use default inactivity and duration timeouts. */ PUBLIC int httpWait(HttpConn *conn, int state, MprTicks timeout) { HttpLimits *limits; MprTicks delay, start; int64 dispatcherMark; int justOne; limits = conn->limits; if (conn->endpoint) { assert(!conn->endpoint); return MPR_ERR_BAD_STATE; } if (conn->state <= HTTP_STATE_BEGIN) { return MPR_ERR_BAD_STATE; } if (state == 0) { /* Wait for just one I/O event */ state = HTTP_STATE_FINALIZED; justOne = 1; } else { justOne = 0; } if (conn->error) { if (conn->state >= state) { return 0; } return MPR_ERR_BAD_STATE; } if (timeout < 0) { timeout = limits->requestTimeout; } else if (timeout == 0) { timeout = MPR_MAX_TIMEOUT; } if (state > HTTP_STATE_CONTENT) { httpFinalizeOutput(conn); } start = conn->http->now; dispatcherMark = mprGetEventMark(conn->dispatcher); while (conn->state < state && !conn->error && !mprIsSocketEof(conn->sock)) { if (httpRequestExpired(conn, -1)) { return MPR_ERR_TIMEOUT; } httpEnableConnEvents(conn); delay = min(limits->inactivityTimeout, mprGetRemainingTicks(start, timeout)); delay = max(delay, 0); mprWaitForEvent(conn->dispatcher, delay, dispatcherMark); if (justOne || (mprGetRemainingTicks(start, timeout) <= 0)) { break; } dispatcherMark = mprGetEventMark(conn->dispatcher); } if (conn->error) { return MPR_ERR_NOT_READY; } if (conn->state < state) { if (mprGetRemainingTicks(start, timeout) <= 0) { return MPR_ERR_TIMEOUT; } if (!justOne) { return MPR_ERR_CANT_READ; } } conn->lastActivity = conn->http->now; return 0; }
/* Wait for the connection to reach a given state. Should only be used on the client side. @param state Desired state. Set to zero if you want to wait for one I/O event. @param timeout Timeout in msec. If timeout is zero, wait forever. If timeout is < 0, use default inactivity and duration timeouts. */ PUBLIC int httpWait(HttpStream *stream, int state, MprTicks timeout) { HttpLimits *limits; MprTicks delay, start; int64 dispatcherMark; int justOne; limits = stream->limits; if (httpServerStream(stream)) { return MPR_ERR_BAD_STATE; } if (stream->state <= HTTP_STATE_BEGIN) { return MPR_ERR_BAD_STATE; } if (state == 0) { /* Wait for just one I/O event */ state = HTTP_STATE_FINALIZED; justOne = 1; } else { justOne = 0; } if (stream->error) { if (stream->state >= state) { return 0; } return MPR_ERR_BAD_STATE; } if (timeout < 0) { timeout = limits->requestTimeout; } else if (timeout == 0) { timeout = MPR_MAX_TIMEOUT; } if (state > HTTP_STATE_CONTENT) { httpFinalizeOutput(stream); } start = stream->http->now; dispatcherMark = mprGetEventMark(stream->dispatcher); // TODO - how does this work with http2? while (stream->state < state && !stream->error && !mprIsSocketEof(stream->sock)) { if (httpRequestExpired(stream, -1)) { return MPR_ERR_TIMEOUT; } // TODO - review httpEnableNetEvents(stream->net); delay = min(limits->inactivityTimeout, mprGetRemainingTicks(start, timeout)); delay = max(delay, 0); mprWaitForEvent(stream->dispatcher, delay, dispatcherMark); if (justOne || (mprGetRemainingTicks(start, timeout) <= 0)) { break; } dispatcherMark = mprGetEventMark(stream->dispatcher); } if (stream->error) { return MPR_ERR_NOT_READY; } if (stream->state < state) { if (mprGetRemainingTicks(start, timeout) <= 0) { return MPR_ERR_TIMEOUT; } if (!justOne) { return MPR_ERR_CANT_READ; } } stream->lastActivity = stream->http->now; return 0; }
static void processProxy(HttpQueue *q) { int count = 50000; q->max = 65536; #if USE0 /* May overflow q->max */ while (sofar < count) { httpWrite(q, "%d aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", sofar++); } httpFinalizeOutput(q->conn); sofar = 0; #endif #if USE1 httpWrite(q, "%d aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", sofar++); if (sofar == count) { httpFinalizeOutput(q->conn); sofar = 0; } #endif #if USE2 while (sofar < count && q->count < (q->max * 3 / 4)) { /* NOTE: httpWrite may do internal flush if count > max */ httpWrite(q, "%d aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", sofar++); } if (sofar == count) { httpFinalizeOutput(q->conn); sofar = 0; } #endif #if USE3 /* MANUAL FLOW CONTROL */ HttpPacket *packet; int i, size; size = 1024; for (; sofar < count && q->count < q->max; sofar++) { packet = httpCreateDataPacket(size); for (i = 1; i < size - 1; i++) { mprPutCharToBuf(packet->content, 'a'); } mprPutCharToBuf(packet->content, '\n'); httpPutForService(q, packet, HTTP_DELAY_SERVICE); } if (sofar == count) { httpFinalizeOutput(q->conn); sofar = 0; } #endif #if USE4 || 1 httpStealConn(q->conn); #endif }