static int process_header_line()

in src/uhttp.c [176:318]


static int process_header_line(const unsigned char* buffer, size_t len, size_t* position, HTTP_HEADERS_HANDLE resp_header, size_t* contentLen, bool* isChunked)
{
    int result = MU_FAILURE;
    size_t index;
    const unsigned char* targetPos = buffer;
    bool crlfEncounted = false;
    bool colonEncountered = false;
    char* headerKey = NULL;
    bool continueProcessing = true;

    for (index = 0; index < len && continueProcessing; index++)
    {
        if (buffer[index] == ':' && !colonEncountered)
        {
            colonEncountered = true;
            size_t keyLen = (&buffer[index]) - targetPos;

            if (keyLen == 0)
            {
                LogError("Invalid header name with zero length.");
                result = MU_FAILURE;
                continueProcessing = false;
            }
            else
            {
                if (headerKey != NULL)
                {
                    free(headerKey);
                    headerKey = NULL;
                }
                size_t malloc_size = safe_add_size_t(keyLen, 1);
                if (malloc_size == SIZE_MAX ||
                    (headerKey = (char*)malloc(malloc_size)) == NULL)
                {
                    LogError("Cannot malloc headerKey, size:%zu", malloc_size);
                    result = MU_FAILURE;
                    continueProcessing = false;
                }
                else
                {
                    memcpy(headerKey, targetPos, keyLen);
                    headerKey[keyLen] = '\0';

                    // Convert to lower case
                    for (size_t inner = 0; inner < keyLen; inner++)
                    {
                        headerKey[inner] = (char)tolower(headerKey[inner]);
                    }

                    targetPos = buffer+index+1;
                    crlfEncounted = false;
                }
            }
        }
        else if (buffer[index] == '\r')
        {
            if (headerKey != NULL)
            {
                // Remove leading spaces
                while (*targetPos == 32) { targetPos++; }

                size_t valueLen = safe_subtract_size_t((&buffer[index]), targetPos);
                size_t malloc_size = safe_add_size_t(valueLen, 1);

                char* headerValue;
                if (malloc_size == SIZE_MAX ||
                    (headerValue = (char*)malloc(malloc_size)) == NULL)
                {
                    LogError("Cannot malloc headerValue, size:%zu", malloc_size);
                    result = MU_FAILURE;
                    continueProcessing = false;
                    headerValue = NULL;
                }
                else
                {
                    memcpy(headerValue, targetPos, valueLen);
                    headerValue[valueLen] = '\0';

                    if (HTTPHeaders_AddHeaderNameValuePair(resp_header, headerKey, headerValue) != HTTP_HEADERS_OK)
                    {
                        result = MU_FAILURE;
                        continueProcessing = false;
                    }
                    else
                    {
                        if (strcmp(headerKey, HTTP_CONTENT_LEN) == 0)
                        {
                            *isChunked = false;
                            *contentLen = atol(headerValue);
                        }
                        else if (strcmp(headerKey, HTTP_TRANSFER_ENCODING) == 0)
                        {
                            *isChunked = true;
                            *contentLen = 0;
                        }
                        if (index < len)
                        {
                            *position = index;
                        }
                        else
                        {
                            *position = index-1;
                        }
                    }
                }
                free(headerKey);
                headerKey = NULL;
                free(headerValue);
            }
        }
        else if (buffer[index] == '\n')
        {
            if (crlfEncounted)
            {
                if (index < len)
                {
                    *position = index+1;
                }
                else
                {
                    *position = index;
                }
                result = 0;
                break;
            }
            else
            {
                colonEncountered = false;
                crlfEncounted = true;
                targetPos = buffer+index+1;
            }
        }
        else
        {
            crlfEncounted = false;
        }
    }
    if (headerKey != NULL)
    {
        free(headerKey);
    }
    return result;
}