/*! * \brief Fills in the Offset, read size and contents to send out as an HTTP * Range Response. * * \return * \li \c HTTP_BAD_REQUEST * \li \c HTTP_INTERNAL_SERVER_ERROR * \li \c HTTP_REQUEST_RANGE_NOT_SATISFIABLE * \li \c HTTP_OK */ static int CreateHTTPRangeResponseHeader( /*! String containing the range. */ char *ByteRangeSpecifier, /*! Length of the file. */ off_t FileLength, /*! [out] SendInstruction object where the range operations will be stored. */ struct SendInstruction *Instr) { off_t FirstByte = 0, LastByte = 0; char *RangeInput; char *Ptr; int rc = 0; int RangeRC; Instr->IsRangeActive = 1; Instr->ReadSendSize = FileLength; if (!ByteRangeSpecifier) return HTTP_BAD_REQUEST; RangeInput = malloc(strlen(ByteRangeSpecifier) + 1); if (!RangeInput) return HTTP_INTERNAL_SERVER_ERROR; memset(RangeInput, 0, strlen(ByteRangeSpecifier) + 1); strncpy(RangeInput, ByteRangeSpecifier, strlen(ByteRangeSpecifier)); /* CONTENT-RANGE: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT */ if (StrStr(RangeInput, "bytes") == NULL || (Ptr = StrStr(RangeInput, "=")) == NULL) { free(RangeInput); Instr->IsRangeActive = 0; return HTTP_BAD_REQUEST; } /* Jump = */ Ptr = Ptr + 1; RangeRC = GetNextRange(&Ptr, &FirstByte, &LastByte); if (FileLength < 0 && LastByte != -1 && LastByte != 1) { free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } if (RangeRC != -1) { if (FileLength < FirstByte && FileLength > 0) { free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } if (FirstByte >= 0 && LastByte == -1 && FileLength < 0) { Instr->RangeOffset = FirstByte; /* UPNP_INFINITE responds with a 200, no need of CONTENT-RANGE */ /* UPNP_UNTIL_CLOSE headers are done in http_SendMessage */ if (FileLength == UPNP_USING_CHUNKED) { rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes %" PRId64 "-" "*" "\r\n", (int64_t)FirstByte); } if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) { free(RangeInput); return HTTP_INTERNAL_SERVER_ERROR; } } else if (FirstByte == 0 && LastByte == 1 && FileLength < 0) { /* client tries to guess length by getting 1 byte but file size is unknown or using chunked */ Instr->RangeOffset = 0; Instr->ReadSendSize = 1; rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes 0-1/*" "\r\n"); if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) { free(RangeInput); return HTTP_INTERNAL_SERVER_ERROR; } } else if (FirstByte >= 0 && LastByte >= 0 && LastByte >= FirstByte) { if (LastByte >= FileLength) LastByte = FileLength - 1; Instr->RangeOffset = FirstByte; Instr->ReadSendSize = LastByte - FirstByte + 1; /* Data between two range. */ rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n", (int64_t)FirstByte, (int64_t)LastByte, (int64_t)FileLength); if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) { free(RangeInput); return HTTP_INTERNAL_SERVER_ERROR; } } else if (FirstByte >= 0 && LastByte == -1 && FirstByte < FileLength) { Instr->RangeOffset = FirstByte; Instr->ReadSendSize = FileLength - FirstByte; rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n", (int64_t)FirstByte, (int64_t)(FileLength - 1), (int64_t)FileLength); if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) { free(RangeInput); return HTTP_INTERNAL_SERVER_ERROR; } } else if (FirstByte == -1 && LastByte > 0) { if (LastByte >= FileLength) { Instr->RangeOffset = 0; Instr->ReadSendSize = FileLength; rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes 0-%" PRId64 "/%" PRId64 "\r\n", (int64_t)(FileLength - 1), (int64_t)FileLength); } else { Instr->RangeOffset = FileLength - LastByte; Instr->ReadSendSize = LastByte; rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n", (int64_t)(FileLength - LastByte), (int64_t)FileLength - 1, (int64_t)FileLength); } if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) { free(RangeInput); return HTTP_INTERNAL_SERVER_ERROR; } } else { free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } } else { free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } free(RangeInput); return HTTP_OK; }
/*! * \brief Fills in the Offset, read size and contents to send out as an HTTP * Range Response. * * \return * \li \c HTTP_BAD_REQUEST * \li \c HTTP_INTERNAL_SERVER_ERROR * \li \c HTTP_REQUEST_RANGE_NOT_SATISFIABLE * \li \c HTTP_OK */ static int CreateHTTPRangeResponseHeader( /*! String containing the range. */ char *ByteRangeSpecifier, /*! Length of the file. */ off_t FileLength, /*! [out] SendInstruction object where the range operations will be stored. */ struct SendInstruction *Instr) { off_t FirstByte, LastByte; char *RangeInput; char *Ptr; int rc = 0; Instr->IsRangeActive = 1; Instr->ReadSendSize = FileLength; if (!ByteRangeSpecifier) return HTTP_BAD_REQUEST; RangeInput = malloc(strlen(ByteRangeSpecifier) + 1); if (!RangeInput) return HTTP_INTERNAL_SERVER_ERROR; memset(RangeInput, 0, strlen(ByteRangeSpecifier) + 1); strncpy(RangeInput, ByteRangeSpecifier, strlen(ByteRangeSpecifier)); /* CONTENT-RANGE: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT */ if (StrStr(RangeInput, "bytes") == NULL || (Ptr = StrStr(RangeInput, "=")) == NULL) { free(RangeInput); Instr->IsRangeActive = 0; return HTTP_BAD_REQUEST; } /* Jump = */ Ptr = Ptr + 1; if (FileLength < 0) { free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } if (GetNextRange(&Ptr, &FirstByte, &LastByte) != -1) { if (FileLength < FirstByte) { free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } if (FirstByte >= 0 && LastByte >= 0 && LastByte >= FirstByte) { if (LastByte >= FileLength) LastByte = FileLength - 1; Instr->RangeOffset = FirstByte; Instr->ReadSendSize = LastByte - FirstByte + 1; /* Data between two range. */ rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n", (int64_t)FirstByte, (int64_t)LastByte, (int64_t)FileLength); if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) { free(RangeInput); return HTTP_INTERNAL_SERVER_ERROR; } } else if (FirstByte >= 0 && LastByte == -1 && FirstByte < FileLength) { Instr->RangeOffset = FirstByte; Instr->ReadSendSize = FileLength - FirstByte; rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n", (int64_t)FirstByte, (int64_t)(FileLength - 1), (int64_t)FileLength); if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) { free(RangeInput); return HTTP_INTERNAL_SERVER_ERROR; } } else if (FirstByte == -1 && LastByte > 0) { if (LastByte >= FileLength) { Instr->RangeOffset = 0; Instr->ReadSendSize = FileLength; rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes 0-%" PRId64 "/%" PRId64 "\r\n", (int64_t)(FileLength - 1), (int64_t)FileLength); } else { Instr->RangeOffset = FileLength - LastByte; Instr->ReadSendSize = LastByte; rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n", (int64_t)(FileLength - LastByte), (int64_t)FileLength - 1, (int64_t)FileLength); } if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) { free(RangeInput); return HTTP_INTERNAL_SERVER_ERROR; } } else { free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } } else { free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } free(RangeInput); return HTTP_OK; }
/*! * \brief Fills in the Offset, read size and contents to send out as an HTTP * Range Response. * * \return * \li \c HTTP_BAD_REQUEST * \li \c HTTP_INTERNAL_SERVER_ERROR * \li \c HTTP_REQUEST_RANGE_NOT_SATISFIABLE * \li \c HTTP_OK */ static int CreateHTTPRangeResponseHeader( /*! String containing the range. */ char *ByteRangeSpecifier, /*! Length of the file. */ off_t FileLength, /*! [out] SendInstruction object where the range operations will be stored. */ struct SendInstruction *Instr) { unsigned long FirstByte, LastByte; char *RangeInput; char *Ptr; int rc = 0; Instr->IsRangeActive = 1; Instr->ReadSendSize = FileLength; if (!ByteRangeSpecifier) return HTTP_BAD_REQUEST; RangeInput = osal_malloc(strlen(ByteRangeSpecifier) + 1); if (!RangeInput) return HTTP_INTERNAL_SERVER_ERROR; strcpy(RangeInput, ByteRangeSpecifier); /* CONTENT-RANGE: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT */ if (StrStr(RangeInput, "bytes") == NULL || (Ptr = StrStr(RangeInput, "=")) == NULL) { osal_free(RangeInput); Instr->IsRangeActive = 0; return HTTP_BAD_REQUEST; } /* Jump = */ Ptr = Ptr + 1; /* * TODO: FileLength is an unsigned long, support ~4G (except -4(UPNP_UNTIL_CLOSE)) if ((int)FileLength < 0) { osal_free(RangeInput); printc("BAD REQUEST: %s %d\r\n", __func__, __LINE__); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } */ if (GetNextRange(&Ptr, (off_t*)&FirstByte, (off_t*)&LastByte) != -1) { if (FileLength < FirstByte) { osal_free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } if (LastByte >= FirstByte) { if (LastByte >= FileLength) LastByte = FileLength - 1; Instr->RangeOffset = FirstByte; Instr->ReadSendSize = LastByte - FirstByte + 1; /* Data between two range. */ rc = snprintf(Instr->RangeHeader, sizeof(Instr->RangeHeader), "CONTENT-RANGE: bytes %" PRId64 "-%" PRId64 "/%" PRId64 "\r\n", (int64_t)FirstByte, (int64_t)LastByte, (int64_t)FileLength); if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) { osal_free(RangeInput); return HTTP_INTERNAL_SERVER_ERROR; } } else { osal_free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } } else { osal_free(RangeInput); return HTTP_REQUEST_RANGE_NOT_SATISFIABLE; } osal_free(RangeInput); return HTTP_OK; }