static void KprWebSocketServerPrepareResponseHeaders(KprWebSocketServerRequest request) { if (NULL == FskHeaderFind(kFskStrServer, request->responseHeaders)) FskHeaderAddString(kFskStrServer, kWebSocketServerIdentifier, request->responseHeaders); if (NULL == FskHeaderFind(kFskStrContentLength, request->responseHeaders)) FskHeaderAddString(kFskStrContentLength, "0", request->responseHeaders); if (NULL == FskHeaderFind(kFskStrDate, request->responseHeaders)) { char dateString[32]; FskTimeMakeDate(dateString, 31); FskHeaderAddString(kFskStrDate, dateString, request->responseHeaders); } }
static int KprWebSocketServerValidateRequest(FskHeaders *requestHeaders, FskHeaders *responseHeaders) { FskErr err; char *value; char *decoded = NULL; UInt32 len; int statusCode = 400; value = FskHeaderFind("Upgrade", requestHeaders); if (!value || FskStrCompareCaseInsensitive(value, "websocket") != 0) goto bail; value = FskHeaderFind("Connection", requestHeaders); if (!value || FskStrCompareCaseInsensitive(value, "Upgrade") != 0) goto bail; value = FskHeaderFind("Sec-WebSocket-Version", requestHeaders); if (!value || FskStrCompare(value, "13") != 0) { statusCode = 426; FskHeaderAddString("Sec-WebSocket-Version", "13", responseHeaders); goto bail; } value = FskHeaderFind("Sec-WebSocket-Key", requestHeaders); if (!value) goto bail; bailIfError(FskStrB64Decode(value, FskStrLen(value), &decoded, &len)); if (len != 16) goto bail; statusCode = 101; bail: FskMemPtrDispose(decoded); return statusCode; }
static void KprWebSocketServerGenerateUpgradeResponse(KprWebSocketServerRequest request) { FskHeaders *responseHeaders = request->responseHeaders; char *encoded = NULL; char *value; responseHeaders->responseCode = 101; FskHeaderAddString("Upgrade", "websocket", responseHeaders); FskHeaderAddString("Connection", "Upgrade", responseHeaders); value = FskHeaderFind("Sec-WebSocket-Key", request->requestHeaders); if (value) { KprWebSocketCalculateHash(value, &encoded); if (encoded) { FskHeaderAddString("Sec-WebSocket-Accept", encoded, responseHeaders); FskMemPtrDispose(encoded); } } }
static FskErr KprWebSocketEndpointUpgradeConnection(KprWebSocketEndpoint self) { FskErr err = kFskErrNone; FskHeaders *request; char buffer[1024], tmp[1024], portStr[10]; int len, port; bailIfError(FskHeaderStructNew(&request)); port = (self->parts->port ? port = self->parts->port : 80); if (port == 80) { FskHeaderAddString("Host", self->parts->host, request); } else { FskStrCopy(tmp, self->parts->host); FskStrCat(tmp, ":"); FskStrNumToStr(port, portStr, 10); FskStrCat(tmp, portStr); FskHeaderAddString("Host", tmp, request); } if (self->origin) { FskHeaderAddString("Origin", self->origin, request); } else { FskStrCopy(tmp, "http://"); FskStrCat(tmp, self->parts->host); FskHeaderAddString("Origin", tmp, request); } FskHeaderAddString("Upgrade", "websocket", request); FskHeaderAddString("Connection", "Upgrade", request); KprWebSocketCreateKey(&self->key); FskHeaderAddString("Sec-WebSocket-Key", self->key, request); FskHeaderAddInteger("Sec-WebSocket-Version", 13, request); FskStrCopy(buffer, "GET "); if (self->parts->path[0] != '/') FskStrCat(buffer, "/"); FskStrCat(buffer, self->parts->path); FskStrCat(buffer, " HTTP/1.1\r\n"); len = FskStrLen(buffer); FskHeaderGenerateOutputBlob(&buffer[len], 1024 - len, true, request); KprSocketWriterSendBytes(self->writer, buffer, FskStrLen(buffer)); bail: return err; }
FskErr mp3SpoolerCallback(void *clientRefCon, UInt32 operation, void *param) { mp3Reader state = clientRefCon; FskErr err = kFskErrNone; switch (operation) { case kFskMediaSpoolerOperationDataReady: state->spoolerPosition += (UInt32)param; if (state->reader->mediaState < kFskMediaPlayerStateStopped) { if (state->id3.data) { UInt32 percent, bytesRead; void *buffer; if (state->id3.size != state->id3.offset) { err = FskMediaSpoolerRead(state->spooler, state->id3.offset, (UInt32)(state->id3.size - state->id3.offset), &buffer, &bytesRead); if (kFskErrNone == err) { FskMemMove((char *)state->id3.data + state->id3.offset, buffer, bytesRead); state->id3.offset += bytesRead; } } percent = (UInt32)((((float)state->id3.offset) / ((float)state->id3.size)) * 100.0); if (percent < 100) (state->reader->doSetState)(state->reader, kFskMediaPlayerStateInstantiatingProgress + percent); else err = mp3Instantiate(state); } else err = mp3Instantiate(state); } break; case kFskMediaSpoolerOperationSetHeaders: { FskHeaders *headers = param; FskHeaderAddString("icy-metadata", "1", headers); } break; case kFskMediaSpoolerOperationGetHeaders: { FskHeaders *headers = param; char *value = FskHeaderFind("icy-metaint", headers); state->icy.metaInt = (NULL != value) ? FskStrToNum(value) : 0; state->icy.nextMetaPosition = state->icy.metaInt; if ((NULL == state->mi.meta) || (kFskErrNone != FskMediaMetaDataGet(state->mi.meta, "FullName", 0, NULL, NULL))) { value = FskHeaderFind("icy-name", headers); if (NULL == value) value = FskHeaderFind("x-audiocast-name", headers); state->icy.title = FskStrDoCopy(value); } state->icy.isProtocol = 0 == FskStrCompare(headers->protocol, "ICY"); value = FskHeaderFind("Server", headers); if (NULL != value) { if (0 == FskStrCompareWithLength("Orbiter", value, 7)) { if (!state->isOrbiter) { state->isOrbiter = true; state->reader->needsIdle = true; FskTimeGetNow(&state->orbStart); } } } if (state->icy.isNanocaster) { value = FskHeaderFind("icy-genre", headers); if ((NULL != value) && (0 == FskStrCompareCaseInsensitive(value, "error"))) (state->reader->doSetState)(state->reader, kFskMediaPlayerStateFailed); } value = FskHeaderFind("availableSeekRange.dlna.org", headers); if (value && (0 == FskStrCompareWithLength("1 npt=", value, 6))) { char *dash = FskStrChr(value + 6, '-'); double duration; if (dash && (kFskErrNone == FskMediaParseNPT(dash + 1, &duration))) state->dlnaDuration = duration; } } break; case kFskMediaSpoolerOperationGetURI: state->spoolerPosition = ((FskMediaSpoolerGetURI)param)->position; break; } return err; }
FskErr KprLibraryServerRequestConditionCallback(FskHTTPServerRequest request, UInt32 condition, void *refCon) { FskErr err = kFskErrNone; KprLibraryServer self = request->http->refCon; KprLibrarySession session = refCon; switch (condition) { case kFskHTTPConditionConnectionInitialized: case kFskHTTPConditionNoSocket: case kFskHTTPConditionRequestReceivedRequestHeaders: break; case kFskHTTPConditionRequestRequestFinished: { FskHeaders *headers; UInt32 queryIndex; KprLibraryQuery query; bailIfError(KprLibrarySessionNew(&session, request)); FskInstrumentedItemSetOwner(session, self); headers = FskHTTPServerRequestGetRequestHeaders(request); queryIndex = FskStrToNum(headers->filename); FskMutexAcquire(self->queryMutex); query = self->queries[queryIndex % kQueryCount]; if (query && (query->index == queryIndex)) { session->info = FskStrDoCopy(query->info); session->kind = query->kind; session->mime = FskStrDoCopy(query->mime); session->url = FskStrDoCopy(query->url); if (query->authorization) session->authorization = FskStrDoCopy(query->authorization); } else err = kFskErrNotFound; FskMutexRelease(self->queryMutex); if (kFskErrNone == err) { KprURLSplit(session->url, &session->parts); if (0 == FskStrCompareWithLength(session->url, "file", 4)) err = KprFileServerOpen(session); else if (0 == FskStrCompareWithLength(session->url, "http", 4)) { session->http.location = FskStrDoCopy(session->url); err = KprProxyServerOpen(session); } else err = KprDataServerOpen(session); } if (kFskErrNeedMoreTime == err) FskHTTPServerRequestSuspend(request); else session->error = err; err = kFskErrNone; } break; case kFskHTTPConditionRequestGenerateResponseHeaders: if (session) { FskHeaders *responseHeaders = FskHTTPServerRequestGetResponseHeaders(request); if (session->error) { if (kFskErrNotFound == session->error) responseHeaders->responseCode = 404; else responseHeaders->responseCode = 500; FskHeaderAddString(kFskStrContentLength, "0", responseHeaders); FskInstrumentedItemPrintfNormal(session, "response headers error %ld", session->error); } else if (session->file.file) KprFileServerGenerateResponseHeaders(session, responseHeaders); else if (session->http.client) KprProxyServerGenerateResponseHeaders(session, responseHeaders); else KprDataServerGenerateResponseHeaders(session, responseHeaders); } break; case kFskHTTPConditionConnectionTerminating: err = kFskErrUnimplemented; //@@ or hang on exit... weird. case kFskHTTPConditionRequestResponseFinished: case kFskHTTPConditionRequestErrorAbort: if (session) KprLibrarySessionDispose(session); break; default: err = kFskErrUnimplemented; break; } bail: return err; }
static void httpPrepareResponseHeaders(FskHTTPServerRequest request) { char *str; int requestProtocolVersion; requestProtocolVersion = FskHeaderHTTPVersion(request->requestHeaders); if (NULL == FskHeaderFind(kFskStrServer, request->responseHeaders)) FskHeaderAddString(kFskStrServer, kHTTPServerIdentifier, request->responseHeaders); str = FskHeaderFind(kFskStrConnection, request->responseHeaders); if (str && FskStrCompareCaseInsensitiveWithLength(str, kFskStrClose, 5) == 0) request->keepAlive = false; str = FskHeaderFind(kFskStrTransferEncoding, request->responseHeaders); if (str && (FskStrCompareCaseInsensitiveWithLength(str, kFskStrChunked, FskStrLen(kFskStrChunked)) == 0)) { request->transferEncoding = kFskTransferEncodingChunked; } else { request->transferEncoding = kFskTransferEncodingNone; str = FskHeaderFind(kFskStrContentLength, request->responseHeaders); if (str) { request->stats.expectedBodyToSend = FskStrToNum(str); } else if (requestProtocolVersion >= kFskHTTPVersion1dot1) { // DHWG 7.8.1 - if http server is responding to 1.1 requests, // it must use connection:close if there's no content length // or chunked encoding FskHeaderRemove(kFskStrConnection, request->responseHeaders); FskHeaderAddString(kFskStrConnection, kFskStrClose, request->responseHeaders); } } if (requestProtocolVersion <= kFskHTTPVersion1dot0) { request->keepAlive = false; // DHWG 7.8.21 (must ignore keepalive) FskHeaderRemove(kFskStrConnection, request->responseHeaders); FskHeaderAddString(kFskStrConnection, kFskStrClose, request->responseHeaders); FskMemPtrDispose(request->requestHeaders->protocol); request->requestHeaders->protocol = FskStrDoCopy("HTTP/1.0"); if (0 == FskStrCompareCaseInsensitiveWithLength(FskHeaderFind(kFskStrTransferEncoding, request->responseHeaders), kFskStrChunked, FskStrLen(kFskStrChunked))) { FskHeaderRemove(kFskStrTransferEncoding, request->responseHeaders); request->transferEncoding = kFskTransferEncodingNone; } if (request->stats.expectedBodyToSend == 0) { FskHeaderRemove(kFskStrConnection, request->responseHeaders); FskHeaderAddString(kFskStrConnection, kFskStrClose, request->responseHeaders); } } if (request->requestHeaders->responseCode >= 400) { request->out.max = snprintf(request->out.buf, request->out.bufferSize, "%s %d %s\r\n", httpProtocolVersionString(request), request->requestHeaders->responseCode, FskFindResponse(request->requestHeaders->responseCode)); } else if (request->responseHeaders->responseCode > 0) { str = FskFindResponse(request->responseHeaders->responseCode); request->out.max = snprintf(request->out.buf, request->out.bufferSize, "%s %d %s\r\n", httpProtocolVersionString(request), request->responseHeaders->responseCode, str ? str : ""); if (request->keepAlive) { FskHeaderRemove(kFskStrConnection, request->responseHeaders); FskHeaderAddString(kFskStrConnection, kFskStrKeepAlive, request->responseHeaders); } } else { request->responseHeaders->responseCode = 500; request->out.max = snprintf(request->out.buf, request->out.bufferSize, "%s 500 Internal Sever Error\r\n", httpProtocolVersionString(request)); } if (NULL == FskHeaderFind(kFskStrDate, request->responseHeaders)) { char dateString[32]; FskTimeMakeDate(dateString, 31); FskHeaderAddString(kFskStrDate, dateString, request->responseHeaders); } // *** generate the response request->out.max += FskHeaderGenerateOutputBlob(&request->out.buf[request->out.max], request->out.bufferSize - request->out.max, true, request->responseHeaders); if ((!request->keepAlive) || (request->responseHeaders->responseCode >= 400)) request->nextState = kHTTPDone; }