/* Handle Trace and Options requests. Handlers can do this themselves if they desire, but typically all Trace/Options requests come here. */ void httpHandleOptionsTrace(HttpConn *conn) { HttpRx *rx; HttpTx *tx; int flags; tx = conn->tx; rx = conn->rx; if (rx->flags & HTTP_TRACE) { /* The trace method is disabled by default unless 'TraceMethod on' is specified */ if (!conn->limits->enableTraceMethod) { tx->status = HTTP_CODE_NOT_ACCEPTABLE; httpFormatResponseBody(conn, "Trace Request Denied", "The TRACE method is disabled on this server."); } else { httpFormatResponse(conn, "%s %s %s\r\n", rx->method, rx->uri, conn->protocol); } /* This finalizes output and indicates the request is now complete */ httpFinalize(conn); } else if (rx->flags & HTTP_OPTIONS) { flags = tx->traceMethods; httpSetHeader(conn, "Allow", "OPTIONS%s%s%s%s%s%s", (conn->limits->enableTraceMethod) ? ",TRACE" : "", (flags & HTTP_STAGE_GET) ? ",GET" : "", (flags & HTTP_STAGE_HEAD) ? ",HEAD" : "", (flags & HTTP_STAGE_POST) ? ",POST" : "", (flags & HTTP_STAGE_PUT) ? ",PUT" : "", (flags & HTTP_STAGE_DELETE) ? ",DELETE" : ""); httpOmitBody(conn); httpSetContentLength(conn, 0); httpFinalize(conn); } }
/* This formats a complete response. Depending on the Accept header, the response will be either HTML or plain text. The response is not HTML escaped. This calls httpFormatResponse. */ PUBLIC ssize httpFormatResponseBody(HttpConn *conn, cchar *title, cchar *fmt, ...) { va_list args; char *msg, *body; va_start(args, fmt); body = fmt ? sfmtv(fmt, args) : conn->errorMsg; if (scmp(conn->rx->accept, "text/plain") == 0) { msg = body; } else { msg = sfmt( "<!DOCTYPE html>\r\n" "<html><head><title>%s</title></head>\r\n" "<body>\r\n%s\r\n</body>\r\n</html>\r\n", title, body); } va_end(args); return httpFormatResponse(conn, "%s", msg); }
/* Redirect the user to another web page. The targetUri may or may not have a scheme. */ PUBLIC void httpRedirect(HttpConn *conn, int status, cchar *targetUri) { HttpTx *tx; HttpRx *rx; HttpUri *target, *base; HttpEndpoint *endpoint; cchar *msg; char *dir, *cp; assert(targetUri); rx = conn->rx; tx = conn->tx; if (tx->finalized) { /* A response has already been formulated */ return; } tx->status = status; if (schr(targetUri, '$')) { targetUri = httpExpandUri(conn, targetUri); } mprLog(3, "redirect %d %s", status, targetUri); msg = httpLookupStatus(conn->http, status); if (300 <= status && status <= 399) { if (targetUri == 0) { targetUri = "/"; } target = httpCreateUri(targetUri, 0); base = rx->parsedUri; /* Support URIs without a host: https:///path. This is used to redirect onto the same host but with a different scheme. So find a suitable local endpoint to supply the port for the scheme. */ if (!target->port && (!target->host || smatch(base->host, target->host)) && (target->scheme && !smatch(target->scheme, base->scheme))) { endpoint = smatch(target->scheme, "https") ? conn->host->secureEndpoint : conn->host->defaultEndpoint; if (endpoint) { target->port = endpoint->port; } else { httpError(conn, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot find endpoint for scheme %s", target->scheme); return; } } if (target->path && target->path[0] != '/') { /* Relative file redirection to a file in the same directory as the previous request. */ dir = sclone(rx->pathInfo); if ((cp = strrchr(dir, '/')) != 0) { /* Remove basename */ *cp = '\0'; } target->path = sjoin(dir, "/", target->path, NULL); } target = httpCompleteUri(target, base); targetUri = httpUriToString(target, 0); httpSetHeader(conn, "Location", "%s", targetUri); httpFormatResponse(conn, "<!DOCTYPE html>\r\n" "<html><head><title>%s</title></head>\r\n" "<body><h1>%s</h1>\r\n<p>The document has moved <a href=\"%s\">here</a>.</p></body></html>\r\n", msg, msg, targetUri); } else { httpFormatResponse(conn, "<!DOCTYPE html>\r\n" "<html><head><title>%s</title></head>\r\n" "<body><h1>%s</h1>\r\n</body></html>\r\n", msg, msg); } httpFinalize(conn); }