Files
AnyPS5/core/libs/prx/libSceHttp/src/Parse.cpp
T
orezraeyandClaude Opus 5.5 77a05cbfe9 fix(libSceHttp): parse status lines past lineLen as measured on a PS5
A payload process on a PS5 (firmware 13.60) parsed 124 status lines and
lengths. It checks lineLen only for its minimum of 8 and for the three
code digits, reads the version and its separators past it, and finds the
line feed up to and including the byte at lineLen, so a length that
stops right before the line feed still parses. When the version ends
past lineLen the unsigned subtractions wrap and the search continues
until a line feed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 08:24:19 -03:00

71 lines
2.5 KiB
C++

#include <cstddef>
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include "prx/libc/include/General.hpp"
#include "prx/libSceHttp/src/HttpErrors.hpp"
namespace {
bool isAsciiDigit(char c) {
return c >= '0' && c <= '9';
}
bool parseVersionNumber(const char* line, size_t& index, int32_t* value) {
if (!isAsciiDigit(line[index])) return false;
uint32_t number = 0;
while (isAsciiDigit(line[index])) {
number = number * 10 + static_cast<uint32_t>(line[index] - '0');
++index;
}
*value = static_cast<int32_t>(number);
return true;
}
}
extern "C" {
int APS5_VABI sceHttpParseStatusLine(const char* statusLine, size_t lineLen, int32_t* httpMajorVer, int32_t* httpMinorVer,
int32_t* responseCode, const char** reasonPhrase, size_t* phraseLen) {
if (!statusLine) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
if (!httpMajorVer || !httpMinorVer || !responseCode || !reasonPhrase || !phraseLen) return ERROR_PARSE_HTTP_INVALID_VALUE;
*httpMajorVer = 0;
*httpMinorVer = 0;
if (lineLen < 8 || std::memcmp(statusLine, "HTTP/", 5) != 0) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
size_t index = 5;
if (!parseVersionNumber(statusLine, index, httpMajorVer)) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
if (statusLine[index] != '.') return ERROR_PARSE_HTTP_INVALID_RESPONSE;
++index;
if (!parseVersionNumber(statusLine, index, httpMinorVer)) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
if (statusLine[index] != ' ') return ERROR_PARSE_HTTP_INVALID_RESPONSE;
++index;
if (lineLen - index < 3) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
if (!isAsciiDigit(statusLine[index]) || !isAsciiDigit(statusLine[index + 1]) || !isAsciiDigit(statusLine[index + 2])) {
return ERROR_PARSE_HTTP_INVALID_RESPONSE;
}
*responseCode = (statusLine[index] - '0') * 100 + (statusLine[index + 1] - '0') * 10 + (statusLine[index + 2] - '0');
index += 3;
const char* phrase = statusLine + index;
const size_t searched = lineLen - index + 1;
size_t length = 0;
while (length != searched && phrase[length] != '\n') ++length;
if (length == searched) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
const size_t consumed = index + length + 1;
if (consumed > static_cast<size_t>(INT32_MAX)) {
throw std::out_of_range("sceHttpParseStatusLine: consumed byte count exceeds int");
}
if (length > 0 && phrase[length - 1] == '\r') --length;
*reasonPhrase = phrase;
*phraseLen = length;
return static_cast<int>(consumed);
}
}