/** * ======================== legal notice ====================== * * File: HTTPResponse.cc * Created: 4. Juli 2012, 06 * Author: Geronimo * Project: libnetworking: classes for tcp/ip sockets and http-protocol handling * * CMP - compound media player * * is a client/server mediaplayer intended to play any media from any workstation * without the need to export or mount shares. cmps is an easy to use backend * with a (ready to use) HTML-interface. Additionally the backend supports * authentication via HTTP-digest authorization. * cmpc is a client with vdr-like osd-menues. * * Copyright (c) 2012 Reinhard Mantey, some rights reserved! * published under Creative Commons by-sa * For details see http://creativecommons.org/licenses/by-sa/3.0/ * * The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp * * -------------------------------------------------------------- */ #include #include #include #include #include static const char *serverID = NULL; cHTTPResponse::cHTTPResponse(HTTPStatusCode Status) : status(Status) , content(512) { SetHeader("Server", serverID); if (!(Status <= HTTP_OK /* || Status == HTTP_NoContent */ || Status == 304)) SetDefaultStatusBody(Status); } cHTTPResponse::cHTTPResponse(const char *Buffer) { ParseMessage(Buffer); if (Authorization()) Authorization()->SetServerID(ServerID()); } cHTTPResponse::~cHTTPResponse() { } size_t cHTTPResponse::ContentSize() const { if (content.Size()) return content.Size(); return cHTTPMessage::ContentSize(); } const char * cHTTPResponse::ServerID(void) { return serverID; } void cHTTPResponse::SetServerID(const char* ServerID) { serverID = ServerID; } void cHTTPResponse::SetDefaultStatusBody(HTTPStatusCode Status) { SetContentType(MT_Html); content.Append("\n" "\n" " \n" " Error "); content.Append(Status).Append("\n" " \n" " \n" "

"); content.Append(Status).Append(" ").Append(httpStatus2Text(Status)).Append(".

\n" "\n"); } void cHTTPResponse::HandleAbort(void) ///< handle cases where client closes connection while transfer was in progress { // default: do nothing } size_t cHTTPResponse::ReadContentChunk(char* Buf, size_t bufSize) { return content.Copy(Buf, bufSize); } size_t cHTTPResponse::WriteFirstLine(char* Buffer, size_t BufSize) { return snprintf(Buffer, BufSize, "%s %d %s\n", ProtocolString(), status, httpStatus2Text(status)); } //static const char *SampleRawResponse = //HTTP/1.1 401 Unauthorized //Date: Tue, 29 May 2012 03:54:02 GMT //Server: (null) //Connection: Close //WWW-Authenticate: Digest realm="validUsers@MyTestApp", nonce="dbe67572c707d25689a394ef7a9a9e8c", opaque="94c70a11bef0589719f190baf192bbcd", qop="auth" //Content-Type: text/html //Content-Length: 301 // // // // Error // // //

401 Unauthorized.

// // void cHTTPResponse::ParseMessage(const char *RawMessage) { char scratch[512]; const char *p = RawMessage; char *tmp; ParseState state = ExpectProtocol; ParseResult status = Continue; Reset(); while (status == Continue) { memset(scratch, 0, sizeof(scratch)); switch (state) { case ExpectStatus: p = getWord(scratch, sizeof(scratch), p); this->status = strtoHTTPStatus(scratch); p = restOfLine(scratch, sizeof(scratch), p); // just read the rest of the line state = ExpectHeader; break; case ExpectProtocol: p = getWord(scratch, sizeof(scratch), p); if (!strcmp(scratch, "HTTP/1.0")) { SetProtocol(HTTP_1_0); state = ExpectStatus; } else if (!strcmp(scratch, "HTTP/1.1")) { SetProtocol(HTTP_1_1); state = ExpectStatus; } else status = UnsupportedProtocol; break; case ExpectContent: printf("should read %ld bytes from %10.10s\n", ContentSize(), p); status = Done; break; case ExpectHeader: p = getWord(scratch, sizeof(scratch), p); if (!strncmp(p, "\n\n", 2)) { p += 2; state = ExpectContent; break; } if (!strncmp(p, "\r\n\r\n", 4)) { p += 4; state = ExpectContent; break; } tmp = scratch + strlen(scratch); if (*(tmp -1) == ':') { *(tmp -1) = 0; tmp = strdup(scratch); p = restOfLine(scratch, sizeof(scratch), p); if (!strcasecmp(tmp, "WWW-Authenticate") || !strcasecmp(tmp, "Authorization-Info")) SetAuthorization(new cAuthorization(cHTTPRequest::GET, scratch)); else if (!strcasecmp(tmp, "content-type")) SetContentType(scratch); else if (!strcasecmp(tmp, "content-length")) SetContentSize(atol(scratch)); else SetHeader(tmp, scratch); FREE(tmp); } else { status = InvalidName; } break; default: break; } // end switch } // end while (status == OK) }