static void setDefaultHeaders(HttpConn *conn) { HttpAuthType *ap; assert(conn); if (smatch(conn->protocol, "HTTP/1.0")) { conn->http10 = 1; } if (conn->username && conn->authType) { if ((ap = httpLookupAuthType(conn->authType)) != 0) { if ((ap->setAuth)(conn, conn->username, conn->password)) { conn->authRequested = 1; } } } if (conn->port != 80 && conn->port != 443) { httpAddHeader(conn, "Host", "%s:%d", conn->ip, conn->port); } else { httpAddHeaderString(conn, "Host", conn->ip); } httpAddHeaderString(conn, "Accept", "*/*"); if (conn->keepAliveCount > 0) { httpSetHeaderString(conn, "Connection", "Keep-Alive"); } else { httpSetHeaderString(conn, "Connection", "close"); } }
static void setDefaultHeaders(HttpStream *stream) { HttpAuthType *ap; assert(stream); if (stream->username && stream->authType && ((ap = httpLookupAuthType(stream->authType)) != 0)) { if ((ap->setAuth)(stream, stream->username, stream->password)) { stream->authRequested = 1; } } if (stream->net->protocol < 2) { if (stream->port != 80 && stream->port != 443) { if (schr(stream->ip, ':')) { httpAddHeader(stream, "Host", "[%s]:%d", stream->ip, stream->port); } else { httpAddHeader(stream, "Host", "%s:%d", stream->ip, stream->port); } } else { httpAddHeaderString(stream, "Host", stream->ip); } if (stream->keepAliveCount > 0) { httpSetHeaderString(stream, "Connection", "Keep-Alive"); } else { httpSetHeaderString(stream, "Connection", "close"); } } httpAddHeaderString(stream, "Accept", "*/*"); }
static void myaction(HttpConn *conn) { HttpQueue *q; q = conn->writeq; /* Set the HTTP response status */ httpSetStatus(conn, 200); /* Add desired headers. "Set" will overwrite, add will create if not already defined. */ httpAddHeaderString(conn, "Content-Type", "text/plain"); httpSetHeaderString(conn, "Cache-Control", "no-cache"); httpWrite(q, "<html><title>simpleAction</title><body>\r\n"); httpWrite(q, "<p>Name: %s</p>\n", httpGetParam(conn, "name", "-")); httpWrite(q, "<p>Address: %s</p>\n", httpGetParam(conn, "address", "-")); httpWrite(q, "</body></html>\r\n"); /* Call finalize output and close the request. Delay closing if you want to do asynchronous output and close later. */ httpFinalize(conn); #if POSSIBLE /* Useful things to do in actions */ httpRedirect(conn, 302, "/other-uri"); httpError(conn, 409, "My message : %d", 5); #endif }
/* Define headers and create an empty header packet that will be filled later by the pipeline. */ static int setClientHeaders(HttpConn *conn) { HttpAuthType *authType; mprAssert(conn); if (smatch(conn->protocol, "HTTP/1.0")) { conn->http10 = 1; } if (conn->authType && (authType = httpLookupAuthType(conn->authType)) != 0) { (authType->setAuth)(conn); conn->setCredentials = 1; } if (conn->port != 80) { httpAddHeader(conn, "Host", "%s:%d", conn->ip, conn->port); } else { httpAddHeaderString(conn, "Host", conn->ip); } #if UNUSED if (conn->http10 && !smatch(conn->tx->method, "GET")) { conn->keepAliveCount = 0; } #endif if (conn->keepAliveCount > 0) { httpSetHeaderString(conn, "Connection", "Keep-Alive"); } else { httpSetHeaderString(conn, "Connection", "close"); } return 0; }
PUBLIC HttpTx *httpCreateTx(HttpConn *conn, MprHash *headers) { HttpTx *tx; if ((tx = mprAllocObj(HttpTx, manageTx)) == 0) { return 0; } conn->tx = tx; tx->conn = conn; tx->status = HTTP_CODE_OK; tx->length = -1; tx->entityLength = -1; tx->chunkSize = -1; tx->queue[HTTP_QUEUE_TX] = httpCreateQueueHead(conn, "TxHead"); conn->writeq = tx->queue[HTTP_QUEUE_TX]->nextQ; tx->queue[HTTP_QUEUE_RX] = httpCreateQueueHead(conn, "RxHead"); conn->readq = tx->queue[HTTP_QUEUE_RX]->prevQ; if (headers) { tx->headers = headers; } else { tx->headers = mprCreateHash(HTTP_SMALL_HASH_SIZE, MPR_HASH_CASELESS); if (!conn->endpoint) { httpAddHeaderString(conn, "User-Agent", sclone(BIT_HTTP_SOFTWARE)); } } return tx; }
/* Add a http header if not already defined */ void espAddHeader(HttpConn *conn, cchar *key, cchar *fmt, ...) { va_list vargs; mprAssert(key && *key); mprAssert(fmt && *fmt); va_start(vargs, fmt); httpAddHeaderString(conn, key, sfmt(fmt, vargs)); va_end(vargs); }
/* The current request has an error and cannot complete as normal. This call sets the Http response status and overrides the normal output with an alternate error message. If the output has alread started (headers sent), then the connection MUST be closed so the client can get some indication the request failed. */ static void errorv(HttpConn *conn, int flags, cchar *fmt, va_list args) { HttpRx *rx; HttpTx *tx; cchar *uri; int status; assert(fmt); rx = conn->rx; tx = conn->tx; if (conn == 0) { return; } status = flags & HTTP_CODE_MASK; if (status == 0) { status = HTTP_CODE_INTERNAL_SERVER_ERROR; } if (flags & (HTTP_ABORT | HTTP_CLOSE)) { conn->keepAliveCount = 0; } if (flags & HTTP_ABORT) { conn->connError = 1; if (rx) { rx->eof = 1; } } if (!conn->error) { conn->error = 1; httpOmitBody(conn); conn->errorMsg = formatErrorv(conn, status, fmt, args); mprLog(2, "Error: %s", conn->errorMsg); HTTP_NOTIFY(conn, HTTP_EVENT_ERROR, 0); if (conn->endpoint) { if (status == HTTP_CODE_NOT_FOUND) { httpMonitorEvent(conn, HTTP_COUNTER_NOT_FOUND_ERRORS, 1); } httpMonitorEvent(conn, HTTP_COUNTER_ERRORS, 1); } httpAddHeaderString(conn, "Cache-Control", "no-cache"); if (conn->endpoint && tx && rx) { if (tx->flags & HTTP_TX_HEADERS_CREATED) { /* If the response headers have been sent, must let the other side of the failure ... aborting the request is the only way as the status has been sent. */ flags |= HTTP_ABORT; } else { if (rx->route && (uri = httpLookupRouteErrorDocument(rx->route, tx->status)) && !smatch(uri, rx->uri)) { errorRedirect(conn, uri); } else { makeAltBody(conn, status); } } } httpFinalize(conn); } if (flags & HTTP_ABORT) { httpDisconnect(conn); } }
/* Add a header string if not already defined */ void espAddHeaderString(HttpConn *conn, cchar *key, cchar *value) { httpAddHeaderString(conn, key, value); }
PUBLIC ssize espRenderRec(HttpConn *conn, EdiRec *rec, int flags) { httpAddHeaderString(conn, "Content-Type", "application/json"); return espRender(conn, "{\"data\": %s, \"schema\": %s}", ediRecAsJson(rec, flags), ediGetRecSchemaAsJson(rec)); }
PUBLIC ssize espRenderGrid(HttpConn *conn, EdiGrid *grid, int flags) { httpAddHeaderString(conn, "Content-Type", "application/json"); return espRender(conn, "{\n \"schema\": %s,\n \"data\": %s}\n", ediGetGridSchemaAsJson(grid), ediGridAsJson(grid, flags)); }
PUBLIC void espShowRequest(HttpConn *conn) { MprHash *env; MprJson *params, *param; MprKey *kp; MprJson *jkey; HttpRx *rx; int i; rx = conn->rx; httpAddHeaderString(conn, "Cache-Control", "no-cache"); httpCreateCGIParams(conn); espRender(conn, "\r\n"); /* Query */ for (ITERATE_JSON(rx->params, jkey, i)) { espRender(conn, "PARAMS %s=%s\r\n", jkey->name, jkey->value ? jkey->value : "null"); } espRender(conn, "\r\n"); /* Http Headers */ env = espGetHeaderHash(conn); for (ITERATE_KEYS(env, kp)) { espRender(conn, "HEADER %s=%s\r\n", kp->key, kp->data ? kp->data: "null"); } espRender(conn, "\r\n"); /* Server vars */ for (ITERATE_KEYS(conn->rx->svars, kp)) { espRender(conn, "SERVER %s=%s\r\n", kp->key, kp->data ? kp->data: "null"); } espRender(conn, "\r\n"); /* Form vars */ if ((params = espGetParams(conn)) != 0) { for (ITERATE_JSON(params, param, i)) { espRender(conn, "FORM %s=%s\r\n", param->name, param->value); } espRender(conn, "\r\n"); } #if KEEP /* Body */ q = conn->readq; if (q->first && rx->bytesRead > 0 && scmp(rx->mimeType, "application/x-www-form-urlencoded") == 0) { buf = q->first->content; mprAddNullToBuf(buf); if ((numKeys = getParams(&keys, mprGetBufStart(buf), (int) mprGetBufLength(buf))) > 0) { for (i = 0; i < (numKeys * 2); i += 2) { value = keys[i+1]; espRender(conn, "BODY %s=%s\r\n", keys[i], value ? value: "null"); } } espRender(conn, "\r\n"); } #endif }
/* Set headers for httpWriteHeaders. This defines standard headers. */ static void setHeaders(HttpConn *conn, HttpPacket *packet) { HttpRx *rx; HttpTx *tx; HttpRoute *route; HttpRange *range; MprKeyValue *item; MprOff length; cchar *mimeType; int next; assert(packet->flags == HTTP_PACKET_HEADER); rx = conn->rx; tx = conn->tx; route = rx->route; /* Mandatory headers that must be defined here use httpSetHeader which overwrites existing values. */ httpAddHeaderString(conn, "Date", conn->http->currentDate); if (tx->ext && route) { if ((mimeType = (char*) mprLookupMime(route->mimeTypes, tx->ext)) != 0) { if (conn->error) { httpAddHeaderString(conn, "Content-Type", "text/html"); } else { httpAddHeaderString(conn, "Content-Type", mimeType); } } } if (tx->etag) { httpAddHeader(conn, "ETag", "%s", tx->etag); } length = tx->length > 0 ? tx->length : 0; if (rx->flags & HTTP_HEAD) { conn->tx->flags |= HTTP_TX_NO_BODY; httpDiscardData(conn, HTTP_QUEUE_TX); if (tx->chunkSize <= 0) { httpAddHeader(conn, "Content-Length", "%Ld", length); } } else if (tx->length < 0 && tx->chunkSize > 0) { httpSetHeaderString(conn, "Transfer-Encoding", "chunked"); } else if (conn->endpoint) { /* Server must not emit a content length header for 1XX, 204 and 304 status */ if (!((100 <= tx->status && tx->status <= 199) || tx->status == 204 || tx->status == 304 || tx->flags & HTTP_TX_NO_LENGTH)) { httpAddHeader(conn, "Content-Length", "%Ld", length); } } else if (tx->length > 0) { /* client with body */ httpAddHeader(conn, "Content-Length", "%Ld", length); } if (tx->outputRanges) { if (tx->outputRanges->next == 0) { range = tx->outputRanges; if (tx->entityLength > 0) { httpSetHeader(conn, "Content-Range", "bytes %Ld-%Ld/%Ld", range->start, range->end - 1, tx->entityLength); } else { httpSetHeader(conn, "Content-Range", "bytes %Ld-%Ld/*", range->start, range->end - 1); } } else { httpSetHeader(conn, "Content-Type", "multipart/byteranges; boundary=%s", tx->rangeBoundary); } httpSetHeader(conn, "Accept-Ranges", "bytes"); } if (conn->endpoint) { if (!(route->flags & HTTP_ROUTE_STEALTH)) { httpAddHeaderString(conn, "Server", conn->http->software); } /* If keepAliveCount == 1 */ if (--conn->keepAliveCount > 0) { assert(conn->keepAliveCount >= 1); httpAddHeaderString(conn, "Connection", "Keep-Alive"); httpAddHeader(conn, "Keep-Alive", "timeout=%Ld, max=%d", conn->limits->inactivityTimeout / 1000, conn->keepAliveCount); } else { /* Tell the peer to close the connection */ httpAddHeaderString(conn, "Connection", "close"); } if (route->flags & HTTP_ROUTE_CORS) { setCorsHeaders(conn); } /* Apply response headers */ for (ITERATE_ITEMS(route->headers, item, next)) { if (item->flags == HTTP_ROUTE_ADD_HEADER) { httpAddHeaderString(conn, item->key, item->value); } else if (item->flags == HTTP_ROUTE_APPEND_HEADER) { httpAppendHeaderString(conn, item->key, item->value); } else if (item->flags == HTTP_ROUTE_REMOVE_HEADER) { httpRemoveHeader(conn, item->key); } else if (item->flags == HTTP_ROUTE_SET_HEADER) { httpSetHeaderString(conn, item->key, item->value); } } } }