{"action":"created","comment":{"url":"https://api.github.com/repos/apple/swift-nio-http2/pulls/comments/241156394","pull_request_review_id":184358055,"id":241156394,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI0MTE1NjM5NA==","diff_hunk":"@@ -0,0 +1,738 @@\n+//\n+//  HTTP2NativeParser.swift\n+//  NIOHTTP2\n+//\n+//  Created by Jim Dovey on 11/14/18.\n+//\n+\n+import NIO\n+import NIOHPACK\n+\n+/// A temporary item used to hold onto the HPACK encoder/decoder. Something in the real stream state engine will\n+/// take its place soon.\n+class HTTP2StreamData {\n+    static private var lookup: Dictionary<HTTP2StreamID, HTTP2StreamData> = [:]\n+    \n+    static func getStream(for streamID: HTTP2StreamID, allocator: ByteBufferAllocator) -> HTTP2StreamData {\n+        if let stream = lookup[streamID] {\n+            return stream\n+        }\n+        \n+        let stream = HTTP2StreamData(streamID: streamID, allocator: allocator)\n+        lookup[streamID] = stream\n+        return stream\n+    }\n+    \n+    var encoder: HPACKEncoder\n+    var decoder: HPACKDecoder\n+    \n+    let streamID: HTTP2StreamID\n+    \n+    init(streamID: HTTP2StreamID, allocator: ByteBufferAllocator) {\n+        // TODO: let's pass through a decent value for table sizes here.\n+        self.encoder = HPACKEncoder(allocator: allocator)\n+        self.decoder = HPACKDecoder(allocator: allocator)\n+        self.streamID = streamID\n+    }\n+    \n+    // internal so tests can see it.\n+    class func reset() {\n+        lookup.removeAll()\n+    }\n+}\n+\n+/// Ingests HTTP/2 data and produces frames. You feed data in, and sometimes you'll get a complete frame out.\n+class HTTP2FrameDecoder {\n+    private var streamDecoders: Dictionary<HTTP2StreamID, HPACKDecoder> = [:]\n+    \n+    private enum ParserState {\n+        case idle\n+        case accumulatingData(FrameHeader, ByteBuffer)\n+    }\n+    \n+    private var state: ParserState = .idle\n+    private var allocator: ByteBufferAllocator\n+    private var currentHeaderFrame: HTTP2Frame? = nil\n+    \n+    /// Creates a new HTTP2 frame decoder.\n+    ///\n+    /// - parameter allocator: A `ByteBufferAllocator` used when accumulating blocks of data\n+    ///                        and decoding headers.\n+    init(allocator: ByteBufferAllocator) {\n+        self.allocator = allocator\n+    }\n+    \n+    \n+    /// Reads at most one frame's worth of bytes from the input buffer, and returns a decoded\n+    /// frame if one has been completely received.\n+    ///\n+    /// The method's effect on the input buffer and its return value depend on the content of\n+    /// the buffer:\n+    ///\n+    /// - If the input buffer contains more bytes beyond the current frame, those bytes will\n+    ///   remain in the buffer; you may continue calling `decode(bytes:)` until the buffer is\n+    ///   empty, or until its size does not change.\n+    /// - If a given buffer does not contain a complete frame header (9 bytes), this method\n+    ///   will take no action, and the buffer will remain unchanged when the method returns.\n+    /// - If the buffer does not contain an entire frame including payload, it will be cached\n+    ///   internally by the decoder, and the next call to `decode(bytes:)` will append any\n+    ///   new bytes to that cache in an effort to complete that frame's payload.\n+    /// - When enough bytes to decode an entire frame have been accumulated or provided, the\n+    ///   resultant frame will be returned. If the entire frame and its payload have not yet\n+    ///   been accumulated, `nil` will be returned.\n+    /// - If we gather enough bytes to construct a frame, but that frame is invalid or malformed,\n+    ///   we consume all the bytes and throw the error specified in RFC 7540.\n+    ///\n+    /// - note: The HTTP/2 protocol specifies that unknown frame types should be ignored. This\n+    ///         implementation will silently collect and drop all bytes associated with frames\n+    ///         whose type is unrecognized; it will not throw an error or otherwise provide\n+    ///         those bytes for processing elsewhere.\n+    ///\n+    /// - Parameter bytes: Raw bytes received, ready to decode. On exit, any consumed bytes\n+    ///                    will no longer be in the buffer.\n+    /// - Returns: A decoded frame type or `nil` if more bytes are needed to complete the frame.\n+    /// - Throws: Errors specified by RFC 7540 § 6 for mis-sized frames or incorrect\n+    ///           stream/connection association.\n+    func decode(bytes: inout ByteBuffer) throws -> HTTP2Frame? {\n+        switch self.state {\n+        case .idle:\n+            return try readPotentialFrame(from: &bytes)","path":"Sources/NIOHTTP2/HTTP2FrameParser.swift","position":99,"original_position":99,"commit_id":"6f2f2cdb11dd1c020bb293acd7bf770c990aebd2","original_commit_id":"6f2f2cdb11dd1c020bb293acd7bf770c990aebd2","user":{"login":"AlanQuatermain","id":11450,"node_id":"MDQ6VXNlcjExNDUw","avatar_url":"https://avatars3.githubusercontent.com/u/11450?v=4","gravatar_id":"","url":"https://api.github.com/users/AlanQuatermain","html_url":"https://github.com/AlanQuatermain","followers_url":"https://api.github.com/users/AlanQuatermain/followers","following_url":"https://api.github.com/users/AlanQuatermain/following{/other_user}","gists_url":"https://api.github.com/users/AlanQuatermain/gists{/gist_id}","starred_url":"https://api.github.com/users/AlanQuatermain/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AlanQuatermain/subscriptions","organizations_url":"https://api.github.com/users/AlanQuatermain/orgs","repos_url":"https://api.github.com/users/AlanQuatermain/repos","events_url":"https://api.github.com/users/AlanQuatermain/events{/privacy}","received_events_url":"https://api.github.com/users/AlanQuatermain/received_events","type":"User","site_admin":false},"body":"Oops 😄","created_at":"2018-12-12T19:34:50Z","updated_at":"2018-12-12T19:34:50Z","html_url":"https://github.com/apple/swift-nio-http2/pull/32#discussion_r241156394","pull_request_url":"https://api.github.com/repos/apple/swift-nio-http2/pulls/32","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/apple/swift-nio-http2/pulls/comments/241156394"},"html":{"href":"https://github.com/apple/swift-nio-http2/pull/32#discussion_r241156394"},"pull_request":{"href":"https://api.github.com/repos/apple/swift-nio-http2/pulls/32"}},"in_reply_to_id":240519925},"pull_request":{"url":"https://api.github.com/repos/apple/swift-nio-http2/pulls/32","id":237455315,"node_id":"MDExOlB1bGxSZXF1ZXN0MjM3NDU1MzE1","html_url":"https://github.com/apple/swift-nio-http2/pull/32","diff_url":"https://github.com/apple/swift-nio-http2/pull/32.diff","patch_url":"https://github.com/apple/swift-nio-http2/pull/32.patch","issue_url":"https://api.github.com/repos/apple/swift-nio-http2/issues/32","number":32,"state":"open","locked":false,"title":"Pure-Swift HTTP2 frame parsers","user":{"login":"AlanQuatermain","id":11450,"node_id":"MDQ6VXNlcjExNDUw","avatar_url":"https://avatars3.githubusercontent.com/u/11450?v=4","gravatar_id":"","url":"https://api.github.com/users/AlanQuatermain","html_url":"https://github.com/AlanQuatermain","followers_url":"https://api.github.com/users/AlanQuatermain/followers","following_url":"https://api.github.com/users/AlanQuatermain/following{/other_user}","gists_url":"https://api.github.com/users/AlanQuatermain/gists{/gist_id}","starred_url":"https://api.github.com/users/AlanQuatermain/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AlanQuatermain/subscriptions","organizations_url":"https://api.github.com/users/AlanQuatermain/orgs","repos_url":"https://api.github.com/users/AlanQuatermain/repos","events_url":"https://api.github.com/users/AlanQuatermain/events{/privacy}","received_events_url":"https://api.github.com/users/AlanQuatermain/received_events","type":"User","site_admin":false},"body":"Motivation:\r\n\r\nPart of the work to remove nghttp2 dependency.\r\n\r\nModifications:\r\n\r\nImplemented frame encoder and decoder types to provide serialization/deserialization:\r\n\r\n* Encoder/Decoder types are distinct reference types, designed to be picked up & used by stream channels or similar.\r\n* Uses NIOHPACK to implement header encoding/decoding. Currently always encodes using Huffman coding, though that could change once we have a `Channel` (and thus `ChannelOptions`) story here.\r\n* Properly decodes padding bytes and flags, and throws errors where padding is broken (e.g. padding size larger than remaining payload size). Currently ignores `PADDED` flag when encoding frames, and never emits padding. If we want this supported via `ChannelOptions` then it can be added later.\r\n* Throws errors from decoder only for data-level issues, like frames being mangled, wrong frame size. Also throws if a stream-specific frame specifies the root (connection) stream or vice-versa.\r\n* Transparently handles incoming `CONTINUATION` frames. When a `HEADERS` frame is decoded which does not have the `END_HEADERS` flag set, that frame is cached in the decoder. Following `CONTINUATION` frames have their headers decoded and appended to those in the cached headers frame. Once we see an `END_HEADERS` flag, we return the complete headers frame as our result.\r\n  - Note that we will throw an error if we see a `CONTINUATION` frame which was not preceded by either a `HEADERS` or a `PUSH_PROMISE` frame.\r\n\r\nSome stop-gap temporary items which will change when this is merged with @Lukasa's changes:\r\n\r\n* `HPACKEncoder`/`HPACKDecoder` types are intended to belong to a HTTP2 Stream. Since that implementation is all changing in @Lukasa's parallel set of changes, I've dropped in a simple lookup table here for now. The intent is NOT for this to go live; it exists for the benefit of the unit tests and to stub out the places in the implementation which would need to reach out & get these HPACK coders from some stream-specific source.\r\n* Custom `NIOHTTP2Errors.ConnectionError` type holding a `NIOHTTP2ErrorCode`. @Lukasa's implementation in #28 is preferred, but I needed a placeholder for this implementation.\r\n\r\nSome frame payload types have changed to accommodate the manual parser:\r\n\r\n* `headers` now contains an `HPACKHeaders` and an optional `StreamPriorityData` rather than a single `HTTPHeaders`.\r\n* `priority` now contains a `StreamPriorityData`.\r\n* `pushPromise` now contains a `HTTP2StreamID` and an `HPACKHeaders`.\r\n\r\nThe new `HTTP2Frame.StreamPriorityData` struct holds the stream dependency information: exclusivity, dependent stream ID, and weight.\r\n\r\nNote that, since the payload types have changed, the live (nghttp2-based) implementation and relevant tests have similarly been updated to use the new encapsulated types.\r\n\r\nThe API is fairly straightforward. The decoder is implemented as a simple funnel: you pass in bytes, they are (usually) consumed, and eventually a frame is emitted once all required bytes have been read. The only exception is if the current byte buffer does not contain enough bytes to construct a frame header (9 bytes), then nothing will happen.\r\n\r\nThe encoder API offers a one-shot method containing an optimization. You hand it a frame and a buffer into which the frame's encoded bytes are to be written. The encoded frame header (9 bytes) will be written into that buffer, as will anything else dynamically encoded by this method. Data already contained in a byte buffer will be returned, in order, as an `[IOData]`. Thus a DATA frame will have its 9-byte header encoded into the input buffer and the `IOData` within the frame's `payload` will be returned. Similarly, HEADERS and PUSH_PROMISE frames, which have their headers encoded to a separate buffer by NIOHPACK, will have the resultant buffers returned via the `[IOData]` return value.\r\n\r\nThe purpose of this trick is to elide some additional copying that isn't strictly necessary; the data is already encoded and can be sent in multiple chunks as-is, without manually copying them into a single monolithic buffer.\r\n\r\nResult:\r\n\r\nThere's now a nice pure-Swift frame encoder/decoder available to use 😊","created_at":"2018-12-10T20:27:23Z","updated_at":"2018-12-12T19:34:50Z","closed_at":null,"merged_at":null,"merge_commit_sha":"15826f45591c0591414a887f2f37f7b4496033a1","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/apple/swift-nio-http2/pulls/32/commits","review_comments_url":"https://api.github.com/repos/apple/swift-nio-http2/pulls/32/comments","review_comment_url":"https://api.github.com/repos/apple/swift-nio-http2/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apple/swift-nio-http2/issues/32/comments","statuses_url":"https://api.github.com/repos/apple/swift-nio-http2/statuses/6f2f2cdb11dd1c020bb293acd7bf770c990aebd2","head":{"label":"AlanQuatermain:parser-implementation","ref":"parser-implementation","sha":"6f2f2cdb11dd1c020bb293acd7bf770c990aebd2","user":{"login":"AlanQuatermain","id":11450,"node_id":"MDQ6VXNlcjExNDUw","avatar_url":"https://avatars3.githubusercontent.com/u/11450?v=4","gravatar_id":"","url":"https://api.github.com/users/AlanQuatermain","html_url":"https://github.com/AlanQuatermain","followers_url":"https://api.github.com/users/AlanQuatermain/followers","following_url":"https://api.github.com/users/AlanQuatermain/following{/other_user}","gists_url":"https://api.github.com/users/AlanQuatermain/gists{/gist_id}","starred_url":"https://api.github.com/users/AlanQuatermain/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AlanQuatermain/subscriptions","organizations_url":"https://api.github.com/users/AlanQuatermain/orgs","repos_url":"https://api.github.com/users/AlanQuatermain/repos","events_url":"https://api.github.com/users/AlanQuatermain/events{/privacy}","received_events_url":"https://api.github.com/users/AlanQuatermain/received_events","type":"User","site_admin":false},"repo":{"id":137252976,"node_id":"MDEwOlJlcG9zaXRvcnkxMzcyNTI5NzY=","name":"swift-nio-http2","full_name":"AlanQuatermain/swift-nio-http2","private":false,"owner":{"login":"AlanQuatermain","id":11450,"node_id":"MDQ6VXNlcjExNDUw","avatar_url":"https://avatars3.githubusercontent.com/u/11450?v=4","gravatar_id":"","url":"https://api.github.com/users/AlanQuatermain","html_url":"https://github.com/AlanQuatermain","followers_url":"https://api.github.com/users/AlanQuatermain/followers","following_url":"https://api.github.com/users/AlanQuatermain/following{/other_user}","gists_url":"https://api.github.com/users/AlanQuatermain/gists{/gist_id}","starred_url":"https://api.github.com/users/AlanQuatermain/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AlanQuatermain/subscriptions","organizations_url":"https://api.github.com/users/AlanQuatermain/orgs","repos_url":"https://api.github.com/users/AlanQuatermain/repos","events_url":"https://api.github.com/users/AlanQuatermain/events{/privacy}","received_events_url":"https://api.github.com/users/AlanQuatermain/received_events","type":"User","site_admin":false},"html_url":"https://github.com/AlanQuatermain/swift-nio-http2","description":"HTTP/2 support for SwiftNIO","fork":true,"url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2","forks_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/forks","keys_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/teams","hooks_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/hooks","issue_events_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/issues/events{/number}","events_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/events","assignees_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/assignees{/user}","branches_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/branches{/branch}","tags_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/tags","blobs_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/git/refs{/sha}","trees_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/statuses/{sha}","languages_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/languages","stargazers_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/stargazers","contributors_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/contributors","subscribers_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/subscribers","subscription_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/subscription","commits_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/commits{/sha}","git_commits_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/git/commits{/sha}","comments_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/comments{/number}","issue_comment_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/issues/comments{/number}","contents_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/contents/{+path}","compare_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/merges","archive_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/downloads","issues_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/issues{/number}","pulls_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/pulls{/number}","milestones_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/milestones{/number}","notifications_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/labels{/name}","releases_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/releases{/id}","deployments_url":"https://api.github.com/repos/AlanQuatermain/swift-nio-http2/deployments","created_at":"2018-06-13T18:07:27Z","updated_at":"2018-11-14T21:38:09Z","pushed_at":"2018-12-10T20:51:40Z","git_url":"git://github.com/AlanQuatermain/swift-nio-http2.git","ssh_url":"git@github.com:AlanQuatermain/swift-nio-http2.git","clone_url":"https://github.com/AlanQuatermain/swift-nio-http2.git","svn_url":"https://github.com/AlanQuatermain/swift-nio-http2","homepage":"","size":444,"stargazers_count":0,"watchers_count":0,"language":"Swift","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"apple:master","ref":"master","sha":"f1d875433faf63f733f614b0c5e5bd1a90677b7d","user":{"login":"apple","id":10639145,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEwNjM5MTQ1","avatar_url":"https://avatars0.githubusercontent.com/u/10639145?v=4","gravatar_id":"","url":"https://api.github.com/users/apple","html_url":"https://github.com/apple","followers_url":"https://api.github.com/users/apple/followers","following_url":"https://api.github.com/users/apple/following{/other_user}","gists_url":"https://api.github.com/users/apple/gists{/gist_id}","starred_url":"https://api.github.com/users/apple/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apple/subscriptions","organizations_url":"https://api.github.com/users/apple/orgs","repos_url":"https://api.github.com/users/apple/repos","events_url":"https://api.github.com/users/apple/events{/privacy}","received_events_url":"https://api.github.com/users/apple/received_events","type":"Organization","site_admin":false},"repo":{"id":123651404,"node_id":"MDEwOlJlcG9zaXRvcnkxMjM2NTE0MDQ=","name":"swift-nio-http2","full_name":"apple/swift-nio-http2","private":false,"owner":{"login":"apple","id":10639145,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEwNjM5MTQ1","avatar_url":"https://avatars0.githubusercontent.com/u/10639145?v=4","gravatar_id":"","url":"https://api.github.com/users/apple","html_url":"https://github.com/apple","followers_url":"https://api.github.com/users/apple/followers","following_url":"https://api.github.com/users/apple/following{/other_user}","gists_url":"https://api.github.com/users/apple/gists{/gist_id}","starred_url":"https://api.github.com/users/apple/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apple/subscriptions","organizations_url":"https://api.github.com/users/apple/orgs","repos_url":"https://api.github.com/users/apple/repos","events_url":"https://api.github.com/users/apple/events{/privacy}","received_events_url":"https://api.github.com/users/apple/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/apple/swift-nio-http2","description":"HTTP/2 support for SwiftNIO","fork":false,"url":"https://api.github.com/repos/apple/swift-nio-http2","forks_url":"https://api.github.com/repos/apple/swift-nio-http2/forks","keys_url":"https://api.github.com/repos/apple/swift-nio-http2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apple/swift-nio-http2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apple/swift-nio-http2/teams","hooks_url":"https://api.github.com/repos/apple/swift-nio-http2/hooks","issue_events_url":"https://api.github.com/repos/apple/swift-nio-http2/issues/events{/number}","events_url":"https://api.github.com/repos/apple/swift-nio-http2/events","assignees_url":"https://api.github.com/repos/apple/swift-nio-http2/assignees{/user}","branches_url":"https://api.github.com/repos/apple/swift-nio-http2/branches{/branch}","tags_url":"https://api.github.com/repos/apple/swift-nio-http2/tags","blobs_url":"https://api.github.com/repos/apple/swift-nio-http2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apple/swift-nio-http2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apple/swift-nio-http2/git/refs{/sha}","trees_url":"https://api.github.com/repos/apple/swift-nio-http2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apple/swift-nio-http2/statuses/{sha}","languages_url":"https://api.github.com/repos/apple/swift-nio-http2/languages","stargazers_url":"https://api.github.com/repos/apple/swift-nio-http2/stargazers","contributors_url":"https://api.github.com/repos/apple/swift-nio-http2/contributors","subscribers_url":"https://api.github.com/repos/apple/swift-nio-http2/subscribers","subscription_url":"https://api.github.com/repos/apple/swift-nio-http2/subscription","commits_url":"https://api.github.com/repos/apple/swift-nio-http2/commits{/sha}","git_commits_url":"https://api.github.com/repos/apple/swift-nio-http2/git/commits{/sha}","comments_url":"https://api.github.com/repos/apple/swift-nio-http2/comments{/number}","issue_comment_url":"https://api.github.com/repos/apple/swift-nio-http2/issues/comments{/number}","contents_url":"https://api.github.com/repos/apple/swift-nio-http2/contents/{+path}","compare_url":"https://api.github.com/repos/apple/swift-nio-http2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apple/swift-nio-http2/merges","archive_url":"https://api.github.com/repos/apple/swift-nio-http2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apple/swift-nio-http2/downloads","issues_url":"https://api.github.com/repos/apple/swift-nio-http2/issues{/number}","pulls_url":"https://api.github.com/repos/apple/swift-nio-http2/pulls{/number}","milestones_url":"https://api.github.com/repos/apple/swift-nio-http2/milestones{/number}","notifications_url":"https://api.github.com/repos/apple/swift-nio-http2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apple/swift-nio-http2/labels{/name}","releases_url":"https://api.github.com/repos/apple/swift-nio-http2/releases{/id}","deployments_url":"https://api.github.com/repos/apple/swift-nio-http2/deployments","created_at":"2018-03-03T02:20:22Z","updated_at":"2018-12-12T18:17:34Z","pushed_at":"2018-12-12T18:17:33Z","git_url":"git://github.com/apple/swift-nio-http2.git","ssh_url":"git@github.com:apple/swift-nio-http2.git","clone_url":"https://github.com/apple/swift-nio-http2.git","svn_url":"https://github.com/apple/swift-nio-http2","homepage":"","size":271,"stargazers_count":141,"watchers_count":141,"language":"Swift","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":15,"mirror_url":null,"archived":false,"open_issues_count":5,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":15,"open_issues":5,"watchers":141,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apple/swift-nio-http2/pulls/32"},"html":{"href":"https://github.com/apple/swift-nio-http2/pull/32"},"issue":{"href":"https://api.github.com/repos/apple/swift-nio-http2/issues/32"},"comments":{"href":"https://api.github.com/repos/apple/swift-nio-http2/issues/32/comments"},"review_comments":{"href":"https://api.github.com/repos/apple/swift-nio-http2/pulls/32/comments"},"review_comment":{"href":"https://api.github.com/repos/apple/swift-nio-http2/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apple/swift-nio-http2/pulls/32/commits"},"statuses":{"href":"https://api.github.com/repos/apple/swift-nio-http2/statuses/6f2f2cdb11dd1c020bb293acd7bf770c990aebd2"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"AlanQuatermain"}}