<commit_before>//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import Foundation
import NIO
import CHTTPParser

public final class HTTPRequestDecoder : ChannelInboundHandler, ByteToMessageDecoder {
    public typealias InboundIn = ByteBuffer
    public typealias InboundOut = HTTPRequest

    var parser: UnsafeMutablePointer<http_parser>?
    var settings: UnsafeMutablePointer<http_parser_settings>?
    public var cumulationBuffer: ByteBuffer?
    
    
    private enum DataAwaitingState {
        case messageBegin
        case url
        case headerField
        case headerValue
        case body
    }

    private var state: HTTPParserState!

    private func writeBytesToBuffer(currentState: DataAwaitingState,
                                    data: UnsafePointer<Int8>!,
                                    len: Int,
                                    previousComplete: (DataAwaitingState) -> Void) -> Void {
        if currentState != self.state.dataAwaitingState {
            let oldState = self.state.dataAwaitingState
            self.state.dataAwaitingState = currentState
            previousComplete(oldState)
        }
        self.state.parserBuffer.write(int8Data: data, len: len)
    }


    private func complete(state: DataAwaitingState) {
        switch state {
        case .messageBegin:
            assert(self.state.parserBuffer.readableBytes == 0, "non-empty buffer on begin (\(self.state.parserBuffer.readableBytes))")
        case .headerField:
            assert(self.state.currentUri != nil, "URI not set before header field")
            self.state.currentHeaderName = self.state.parserBuffer.readString()!
            self.state.parserBuffer.clear()
        case .headerValue:
            assert(self.state.currentUri != nil, "URI not set before header field")
            self.state.currentHeaders.add(name: self.state.currentHeaderName!, value: self.state.parserBuffer.readString()!)
            self.state.parserBuffer.clear()
        case .url:
            assert(self.state.currentUri == nil)
            self.state.currentUri = self.state.parserBuffer.readString()!
            self.state.parserBuffer.clear()
        case .body:
            ()
        }
    }

    private struct HTTPParserState {
        var dataAwaitingState: DataAwaitingState = .messageBegin
        var currentHeaders = HTTPHeaders()
        var currentUri: String?
        var currentHeaderName: String?
        var parserBuffer: ByteBuffer

        mutating func reset() {
            self.currentHeaders = HTTPHeaders()
            self.currentUri = nil
            self.currentHeaderName = nil
            self.parserBuffer.clear()
        }

        mutating func finializeHTTPRequest(parser: UnsafeMutablePointer<http_parser>?) -> HTTPRequestHead? {
            guard let method = HTTPMethod.from(httpParserMethod: http_method(rawValue: parser!.pointee.method)) else {
                return nil
            }
            let version = HTTPVersion(major: parser!.pointee.http_minor, minor: parser!.pointee.http_major)
            let request = HTTPRequestHead(version: version, method: method, uri: currentUri!, headers: currentHeaders)
            currentHeaders = HTTPHeaders()
            return request
        }

        init(allocator: ByteBufferAllocator) throws {
            self.parserBuffer = allocator.buffer(capacity: 64)
        }
    }

    public init() { }

    public func decoderAdded(ctx: ChannelHandlerContext) throws {
        parser = UnsafeMutablePointer<http_parser>.allocate(capacity: 1)
        http_parser_init(parser, HTTP_REQUEST)
        parser!.pointee.data = Unmanaged.passUnretained(ctx).toOpaque()

        settings = UnsafeMutablePointer<http_parser_settings>.allocate(capacity: 1)
        http_parser_settings_init(settings)

        self.state = try HTTPParserState(allocator: ctx.channel!.allocator)<commit_msg>Correctly build HTTPVersion and dont create HTTPHeaders if not needed<commit_after>//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import Foundation
import NIO
import CHTTPParser

public final class HTTPRequestDecoder : ByteToMessageDecoder {
    public typealias InboundIn = ByteBuffer
    public typealias InboundOut = HTTPRequest

    var parser: UnsafeMutablePointer<http_parser>?
    var settings: UnsafeMutablePointer<http_parser_settings>?
    public var cumulationBuffer: ByteBuffer?
    
    
    private enum DataAwaitingState {
        case messageBegin
        case url
        case headerField
        case headerValue
        case body
    }

    private var state: HTTPParserState!

    private func writeBytesToBuffer(currentState: DataAwaitingState,
                                    data: UnsafePointer<Int8>!,
                                    len: Int,
                                    previousComplete: (DataAwaitingState) -> Void) -> Void {
        if currentState != self.state.dataAwaitingState {
            let oldState = self.state.dataAwaitingState
            self.state.dataAwaitingState = currentState
            previousComplete(oldState)
        }
        self.state.parserBuffer.write(int8Data: data, len: len)
    }


    private func complete(state: DataAwaitingState) {
        switch state {
        case .messageBegin:
            assert(self.state.parserBuffer.readableBytes == 0, "non-empty buffer on begin (\(self.state.parserBuffer.readableBytes))")
        case .headerField:
            assert(self.state.currentUri != nil, "URI not set before header field")
            self.state.currentHeaderName = self.state.parserBuffer.readString()!
            self.state.parserBuffer.clear()
        case .headerValue:
            assert(self.state.currentUri != nil, "URI not set before header field")
            self.state.currentHeaders!.add(name: self.state.currentHeaderName!, value: self.state.parserBuffer.readString()!)
            self.state.parserBuffer.clear()
        case .url:
            assert(self.state.currentUri == nil)
            self.state.currentUri = self.state.parserBuffer.readString()!
            self.state.parserBuffer.clear()
        case .body:
            ()
        }
    }

    private struct HTTPParserState {
        var dataAwaitingState: DataAwaitingState = .messageBegin
        var currentHeaders: HTTPHeaders?
        var currentUri: String?
        var currentHeaderName: String?
        var parserBuffer: ByteBuffer

        mutating func reset() {
            self.currentHeaders = HTTPHeaders()
            self.currentUri = nil
            self.currentHeaderName = nil
            self.parserBuffer.clear()
        }

        mutating func finializeHTTPRequest(parser: UnsafeMutablePointer<http_parser>?) -> HTTPRequestHead? {
            guard let method = HTTPMethod.from(httpParserMethod: http_method(rawValue: parser!.pointee.method)) else {
                return nil
            }
            let version = HTTPVersion(major: parser!.pointee.http_major, minor: parser!.pointee.http_minor)
            let request = HTTPRequestHead(version: version, method: method, uri: currentUri!, headers: currentHeaders!)
            currentHeaders = nil
            return request
        }

        init(allocator: ByteBufferAllocator) throws {
            self.parserBuffer = allocator.buffer(capacity: 64)
        }
    }

    public init() { }

    public func decoderAdded(ctx: ChannelHandlerContext) throws {
        parser = UnsafeMutablePointer<http_parser>.allocate(capacity: 1)
        http_parser_init(parser, HTTP_REQUEST)
        parser!.pointee.data = Unmanaged.passUnretained(ctx).toOpaque()

        settings = UnsafeMutablePointer<http_parser_settings>.allocate(capacity: 1)
        http_parser_settings_init(settings)

        self.state = try HTTPParserState(allocator: ctx.channel!.allocator)
{'fraction_non_alphanumeric': 0.11616918289731475, 'fraction_numerical': 0.004379393799700358, 'mean_word_length': 2.1974944731024317, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6867878', 'n_tokens_mistral': 2262, 'n_tokens_neox': 2166, 'n_words': 523}