!C99Shell v. 2.0 [PHP 7 Update] [25.02.2019]!

Software: Apache. PHP/5.6.40 

uname -a: Linux cpanel06wh.bkk1.cloud.z.com 2.6.32-954.3.5.lve1.4.80.el6.x86_64 #1 SMP Thu Sep 24
01:42:00 EDT 2020 x86_64
 

uid=851(cp949260) gid=853(cp949260) groups=853(cp949260) 

Safe-mode: OFF (not secure)

/opt/passenger-5.3.7-4.el6.cloudlinux/src/cxx_supportlib/ServerKit/   drwxr-xr-x
Free 234.19 GB of 981.82 GB (23.85%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     HttpHeaderParser.h (17.54 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 *  Phusion Passenger - https://www.phusionpassenger.com/
 *  Copyright (c) 2014-2018 Phusion Holding B.V.
 *
 *  "Passenger", "Phusion Passenger" and "Union Station" are registered
 *  trademarks of Phusion Holding B.V.
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *  THE SOFTWARE.
 */
#ifndef _PASSENGER_SERVER_KIT_HTTP_HEADER_PARSER_H_
#define _PASSENGER_SERVER_KIT_HTTP_HEADER_PARSER_H_

#include <boost/cstdint.hpp>
#include <oxt/backtrace.hpp>
#include <cstddef>
#include <cassert>
#include <cstring>
#include <MemoryKit/mbuf.h>
#include <ServerKit/Context.h>
#include <ServerKit/HttpRequest.h>
#include <ServerKit/HttpHeaderParserState.h>
#include <DataStructures/LString.h>
#include <DataStructures/HashedStaticString.h>
#include <LoggingKit/LoggingKit.h>
#include <StrIntTools/StrIntUtils.h>
#include <Algorithms/Hasher.h>

namespace Passenger {
namespace ServerKit {


extern const HashedStaticString HTTP_CONTENT_LENGTH;
extern const HashedStaticString HTTP_TRANSFER_ENCODING;
extern const HashedStaticString HTTP_X_SENDFILE;
extern const HashedStaticString HTTP_X_ACCEL_REDIRECT;

struct HttpParseRequest {};
struct HttpParseResponse {};

template<typename Message, typename MessageType = HttpParseRequest>
class HttpHeaderParser {
private:
    Context *ctx;
    HttpHeaderParserState *state;
    Message *message;
    psg_pool_t *pool;
    const MemoryKit::mbuf *currentBuffer;
    http_method    requestMethod;

    bool validateHeader(const HttpParseRequest &tag, const Header *header) {
        if (!state->secureMode) {
            if (!psg_lstr_cmp(&header->key, P_STATIC_STRING("!~"), 2)) {
                return true;
            } else {
                if (header->key.size == 2) {
                    // Security password. Check whether it hasn't been
                    // given before and whether it is correct.
                    if (ctx->config.secureModePassword.empty()
                     || psg_lstr_cmp(&header->val, ctx->config.secureModePassword))
                    {
                        state->secureMode = true;
                        return true;
                    } else {
                        state->state = HttpHeaderParserState::ERROR_SECURITY_PASSWORD_MISMATCH;
                        return false;
                    }
                } else {
                    // Secure header encountered without having
                    // encountered a security password.
                    state->state = HttpHeaderParserState::ERROR_SECURE_HEADER_NOT_ALLOWED;
                    return false;
                }
            }
        } else {
            if (psg_lstr_cmp(&header->key, P_STATIC_STRING("!~"), 2)) {
                if (header->key.size == 2) {
                    state->secureMode = false;
                }
                return true;
            } else {
                // To prevent Internet clients from injecting secure headers,
                // we require the web server put secure headers between a begin
                // marker (the security password header) and an end marker.
                // If we find a normal header between the markers, then we
                // can assume the web server is bugged or compromised.
                state->state = HttpHeaderParserState::ERROR_NORMAL_HEADER_NOT_ALLOWED_AFTER_SECURITY_PASSWORD;
                return false;
            }
        }
    }

    bool validateHeader(const HttpParseResponse &tag, const Header *header) {
        state->secureMode = psg_lstr_cmp(&header->key, P_STATIC_STRING("!~"), 2);
        return true;
    }

    void insertCurrentHeader() {
        if (!state->secureMode) {
            message->headers.insert(&state->currentHeader, pool);
        } else {
            message->secureHeaders.insert(&state->currentHeader, pool);
        }
    }

    static size_t http_parser_execute_and_handle_pause(http_parser *parser,
        const http_parser_settings *settings, const char *data, size_t len,
        bool &paused)
    {
        size_t ret = http_parser_execute(parser, settings, data, len);
        paused = len > 0 && ret != len && HTTP_PARSER_ERRNO(parser) == HPE_PAUSED;
        if (paused) {
            http_parser_pause(parser, 0);
            http_parser_execute(parser, settings, data + len - 1, 1);
        }
        return ret;
    }

    static int _onURL(http_parser *parser, const char *data, size_t len) {
        HttpHeaderParser *self = static_cast<HttpHeaderParser *>(parser->data);
        return self->onURL(MessageType(), data, len);
    }

    OXT_FORCE_INLINE
    int onURL(const HttpParseRequest &tag, const char *data, size_t len) {
        state->state = HttpHeaderParserState::PARSING_URL;
        psg_lstr_append(&message->path, pool, *currentBuffer, data, len);
        return 0;
    }

    OXT_FORCE_INLINE
    int onURL(const HttpParseResponse &tag, const char *data, size_t len) {
        P_BUG("Should never be called");
        return 0;
    }

    static int onStatus(http_parser *parser, const char *data, size_t len) {
        HttpHeaderParser *self = static_cast<HttpHeaderParser *>(parser->data);
        if (parser->status_code == 100) {
            self->set100ContinueHttpState(MessageType());
            http_parser_pause(parser, 1);
        }
        return 0;
    }

    void set100ContinueHttpState(const HttpParseRequest &tag) {
        P_BUG("Should never be called");
    }

    void set100ContinueHttpState(const HttpParseResponse &tag) {
        message->httpState = Message::ONEHUNDRED_CONTINUE;
    }

    static int onHeaderField(http_parser *parser, const char *data, size_t len) {
        HttpHeaderParser *self = static_cast<HttpHeaderParser *>(parser->data);

        if (self->state->state == HttpHeaderParserState::PARSING_NOT_STARTED
         || self->state->state == HttpHeaderParserState::PARSING_URL
         || self->state->state == HttpHeaderParserState::PARSING_HEADER_VALUE
         || self->state->state == HttpHeaderParserState::PARSING_FIRST_HEADER_VALUE)
        {
            // New header field encountered.

            if (self->state->state == HttpHeaderParserState::PARSING_FIRST_HEADER_VALUE
             || self->state->state == HttpHeaderParserState::PARSING_HEADER_VALUE)
            {
                // Validate previous header and insert into table.
                if (!self->validateHeader(MessageType(), self->state->currentHeader)) {
                    return 1;
                }
                self->insertCurrentHeader();
            }

            // Initialize new header field.
            self->state->currentHeader = (Header *) psg_palloc(self->pool, sizeof(Header));
            psg_lstr_init(&self->state->currentHeader->key);
            psg_lstr_init(&self->state->currentHeader->origKey);
            psg_lstr_init(&self->state->currentHeader->val);
            self->state->hasher.reset();
            if (self->state->state == HttpHeaderParserState::PARSING_URL) {
                self->state->state = HttpHeaderParserState::PARSING_FIRST_HEADER_FIELD;
            } else {
                self->state->state = HttpHeaderParserState::PARSING_HEADER_FIELD;
            }
        }

        psg_lstr_append(&self->state->currentHeader->origKey, self->pool,
            *self->currentBuffer, data, len);
        if (psg_lstr_first_byte(&self->state->currentHeader->origKey) == '!') {
            psg_lstr_append(&self->state->currentHeader->key, self->pool,
                *self->currentBuffer, data, len);
            self->state->hasher.update(data, len);
        } else {
            char *downcasedData = (char *) psg_pnalloc(self->pool, len);
            convertLowerCase((const unsigned char *) data,
                (unsigned char *) downcasedData, len);
            psg_lstr_append(&self->state->currentHeader->key, self->pool,
                downcasedData, len);
            self->state->hasher.update(downcasedData, len);
        }

        return 0;
    }

    static int onHeaderValue(http_parser *parser, const char *data, size_t len) {
        HttpHeaderParser *self = static_cast<HttpHeaderParser *>(parser->data);

        if (self->state->state == HttpHeaderParserState::PARSING_FIRST_HEADER_FIELD
         || self->state->state == HttpHeaderParserState::PARSING_HEADER_FIELD)
        {
            // New header value encountered. Finalize corresponding header field.
            if (self->state->state == HttpHeaderParserState::PARSING_FIRST_HEADER_FIELD) {
                self->state->state = HttpHeaderParserState::PARSING_FIRST_HEADER_VALUE;
            } else {
                self->state->state = HttpHeaderParserState::PARSING_HEADER_VALUE;
            }
            self->state->currentHeader->hash = self->state->hasher.finalize();

        }

        psg_lstr_append(&self->state->currentHeader->val, self->pool,
            *self->currentBuffer, data, len);
        self->state->hasher.update(data, len);

        return 0;
    }

    static int onHeadersComplete(http_parser *parser) {
        HttpHeaderParser *self = static_cast<HttpHeaderParser *>(parser->data);

        if (self->state->state == HttpHeaderParserState::PARSING_HEADER_VALUE
         || self->state->state == HttpHeaderParserState::PARSING_FIRST_HEADER_VALUE)
        {
            // Validate previous header and insert into table.
            if (!self->validateHeader(MessageType(), self->state->currentHeader)) {
                // There's a bug in http_parser: even if we return 1 here, it doesn't
                // set the error flag correctly. We fix that here.
                self->state->parser.http_errno = HPE_CB_headers_complete;
                return 1;
            }
            self->insertCurrentHeader();
        }

        self->state->currentHeader = NULL;
        self->message->httpState = Message::PARSED_HEADERS;
        self->indexQueryString(MessageType());
        http_parser_pause(parser, 1);
        return 0;
    }

    OXT_FORCE_INLINE
    void indexQueryString(const HttpParseRequest &tag) {
        LString *contiguousPath = psg_lstr_make_contiguous(&message->path,
            message->pool);
        if (contiguousPath != &message->path) {
            psg_lstr_deinit(&message->path);
            message->path = *contiguousPath;
        }

        const char *pos = (const char *) memchr(message->path.start->data, '?',
            message->path.size);
        if (pos != NULL) {
            message->queryStringIndex = pos - message->path.start->data;
        }
    }

    OXT_FORCE_INLINE
    void indexQueryString(const HttpParseResponse &tag) {
        // Do nothing.
    }

    OXT_FORCE_INLINE
    void initializeParser(const HttpParseRequest &tag) {
        http_parser_init(&state->parser, HTTP_REQUEST);
    }

    OXT_FORCE_INLINE
    void initializeParser(const HttpParseResponse &tag) {
        http_parser_init(&state->parser, HTTP_RESPONSE);
    }

    OXT_FORCE_INLINE
    bool messageHttpStateIndicatesCompletion(const HttpParseRequest &tag) const {
        return message->httpState == Message::PARSED_HEADERS;
    }

    OXT_FORCE_INLINE
    bool messageHttpStateIndicatesCompletion(const HttpParseResponse &tag) const {
        return message->httpState == Message::PARSED_HEADERS
            || message->httpState == Message::ONEHUNDRED_CONTINUE;
    }

    void processParseResult(const HttpParseRequest &tag) {
        TRACE_POINT();
        bool isChunked = state->parser.flags & F_CHUNKED;
        boost::uint64_t contentLength;
        int httpVersion;

        // The parser sets content_length to ULLONG_MAX if
        // Content-Length is not given. We treat it the same as 0.
        contentLength = state->parser.content_length;
        if (contentLength == std::numeric_limits<boost::uint64_t>::max()) {
            contentLength = 0;
        }

        message->method = (http_method) state->parser.method;
        httpVersion = state->parser.http_major * 1000 + state->parser.http_minor * 10;

        if (httpVersion > 1010) {
            // Maximum supported HTTP version is 1.1
            message->httpState      = Message::ERROR;
            message->aux.parseError = HTTP_VERSION_NOT_SUPPORTED;
            message->httpMajor      = 1;
            message->httpMinor      = 1;
            message->wantKeepAlive  = false;
        } else if (contentLength > 0 && isChunked) {
            message->httpState  = Message::ERROR;
            message->aux.parseError = REQUEST_CONTAINS_CONTENT_LENGTH_AND_TRANSFER_ENCODING;
        } else if (contentLength > 0 || isChunked) {
            // There is a request body.
            message->aux.bodyInfo.contentLength = contentLength;
            if (state->parser.upgrade) {
                message->httpState      = Message::ERROR;
                message->aux.parseError = UPGRADE_NOT_ALLOWED_WHEN_REQUEST_BODY_EXISTS;
            } else if (isChunked) {
                message->httpState = Message::PARSING_CHUNKED_BODY;
                message->bodyType  = Message::RBT_CHUNKED;
            } else {
                message->httpState = Message::PARSING_BODY;
                message->bodyType  = Message::RBT_CONTENT_LENGTH;
            }
        } else {
            // There is no request body.
            if (!state->parser.upgrade) {
                message->httpState = Message::COMPLETE;
                P_ASSERT_EQ(message->bodyType, Message::RBT_NO_BODY);
            } else if (message->method != HTTP_HEAD) {
                message->httpState = Message::UPGRADED;
                message->bodyType  = Message::RBT_UPGRADE;
                message->wantKeepAlive = false;
            } else {
                message->httpState      = Message::ERROR;
                message->aux.parseError = UPGRADE_NOT_ALLOWED_FOR_HEAD_REQUESTS;
            }
        }
    }

    void processParseResult(const HttpParseResponse &tag) {
        TRACE_POINT();
        const unsigned int status = state->parser.status_code;
        const boost::uint64_t contentLength = state->parser.content_length;

        message->statusCode = state->parser.status_code;

        if (state->parser.upgrade) {
            message->httpState = Message::UPGRADED;
            message->bodyType  = Message::RBT_UPGRADE;
            message->wantKeepAlive = false;
        } else if (message->headers.lookup(HTTP_X_SENDFILE) != NULL
         || message->headers.lookup(HTTP_X_ACCEL_REDIRECT) != NULL)
        {
            // If X-Sendfile or X-Accel-Redirect is set, pretend like the body
            // is empty and disallow keep-alive. See:
            // https://github.com/phusion/passenger/issues/1376
            // https://github.com/phusion/passenger/issues/1498
            //
            // We don't set a fake "Content-Length: 0" header here
            // because it's undefined what Content-Length means if
            // X-Sendfile or X-Accel-Redirect are set.
            //
            // Because the response header no longer has any header
            // that signals its size, keep-alive should also be disabled
            // for the *request*. We already do that in RequestHandler's
            // ForwardResponse.cpp.
            message->httpState = Message::COMPLETE;
            message->bodyType = Message::RBT_NO_BODY;
            message->headers.erase(HTTP_CONTENT_LENGTH);
            message->headers.erase(HTTP_TRANSFER_ENCODING);
            message->wantKeepAlive = false;
        } else if (requestMethod == HTTP_HEAD
         || status / 100 == 1  // status 1xx
         || status == 204
         || status == 304)
        {
            if (status != 100) {
                message->httpState = Message::COMPLETE;
            } else {
                message->httpState = Message::ONEHUNDRED_CONTINUE;
            }
            message->bodyType = Message::RBT_NO_BODY;
        } else if (state->parser.flags & F_CHUNKED) {
            if (contentLength == std::numeric_limits<boost::uint64_t>::max()) {
                message->httpState = Message::PARSING_CHUNKED_BODY;
                message->bodyType  = Message::RBT_CHUNKED;
            } else {
                message->httpState      = Message::ERROR;
                message->aux.parseError = RESPONSE_CONTAINS_CONTENT_LENGTH_AND_TRANSFER_ENCODING;
            }
        } else if (contentLength == 0) {
            message->httpState = Message::COMPLETE;
            message->bodyType  = Message::RBT_NO_BODY;
        } else if (contentLength != std::numeric_limits<boost::uint64_t>::max()) {
            message->httpState = Message::PARSING_BODY_WITH_LENGTH;
            message->bodyType  = Message::RBT_CONTENT_LENGTH;
            message->aux.bodyInfo.contentLength = contentLength;
        } else {
            message->httpState = Message::PARSING_BODY_UNTIL_EOF;
            message->bodyType  = Message::RBT_UNTIL_EOF;
            message->wantKeepAlive = false;
        }
    }

public:
    HttpHeaderParser(Context *context, HttpHeaderParserState *_state,
        Message *_message, psg_pool_t *_pool,
        enum http_method _requestMethod = HTTP_GET)
        : ctx(context),
          state(_state),
          message(_message),
          pool(_pool),
          currentBuffer(NULL),
          requestMethod(_requestMethod)
        { }

    void initialize() {
        initializeParser(MessageType());
        state->state = HttpHeaderParserState::PARSING_NOT_STARTED;
        state->secureMode = false;
    }

    size_t feed(const MemoryKit::mbuf &buffer) {
        TRACE_POINT();
        P_ASSERT_EQ(message->httpState, Message::PARSING_HEADERS);

        http_parser_settings settings;
        size_t ret;
        bool paused;

        settings.on_message_begin = NULL;
        settings.on_url = _onURL;
        settings.on_status = onStatus;
        settings.on_header_field = onHeaderField;
        settings.on_header_value = onHeaderValue;
        settings.on_headers_complete = onHeadersComplete;
        settings.on_body = NULL;
        settings.on_message_complete = NULL;

        state->parser.data = this;
        currentBuffer = &buffer;
        ret = http_parser_execute_and_handle_pause(&state->parser,
            &settings, buffer.start, buffer.size(), paused);
        currentBuffer = NULL;

        if (!state->parser.upgrade && ret != buffer.size() && !paused) {
            UPDATE_TRACE_POINT();
            message->httpState = Message::ERROR;
            switch (HTTP_PARSER_ERRNO(&state->parser)) {
            case HPE_CB_header_field:
            case HPE_CB_headers_complete:
                switch (state->state) {
                case HttpHeaderParserState::ERROR_SECURITY_PASSWORD_MISMATCH:
                    message->aux.parseError = SECURITY_PASSWORD_MISMATCH;
                    break;
                case HttpHeaderParserState::ERROR_SECURITY_PASSWORD_DUPLICATE:
                    message->aux.parseError = SECURITY_PASSWORD_DUPLICATE;
                    break;
                case HttpHeaderParserState::ERROR_SECURE_HEADER_NOT_ALLOWED:
                    message->aux.parseError = ERROR_SECURE_HEADER_NOT_ALLOWED;
                    break;
                case HttpHeaderParserState::ERROR_NORMAL_HEADER_NOT_ALLOWED_AFTER_SECURITY_PASSWORD:
                    message->aux.parseError = NORMAL_HEADER_NOT_ALLOWED_AFTER_SECURITY_PASSWORD;
                    break;
                default:
                    goto default_error;
                }
                break;
            default:
                default_error:
                message->aux.parseError = HTTP_PARSER_ERRNO_BEGIN - HTTP_PARSER_ERRNO(&state->parser);
                break;
            }
        } else if (messageHttpStateIndicatesCompletion(MessageType())) {
            UPDATE_TRACE_POINT();
            ret++;
            message->httpMajor = state->parser.http_major;
            message->httpMinor = state->parser.http_minor;
            message->wantKeepAlive = http_should_keep_alive(&state->parser);
            processParseResult(MessageType());
        }

        return ret;
    }
};


} // namespace ServerKit
} // namespace Passenger

#endif /* _PASSENGER_SERVER_KIT_HTTP_HEADER_PARSER_H_ */

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.0 [PHP 7 Update] [25.02.2019] maintained by KaizenLouie | C99Shell Github | Generation time: 0.0139 ]--