# Copyright (c) 2019 Cloudflare, Inc. and contributors # Licensed under the MIT License: # # 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. @0xb665280aaff2e632; # Cap'n Proto interface for HTTP. using import "byte-stream.capnp".ByteStream; $import "/capnp/c++.capnp".namespace("capnp"); interface HttpService { startRequest @0 (request :HttpRequest, context :ClientRequestContext) -> (requestBody :ByteStream, context :ServerRequestContext); # Begin an HTTP request. # # The client sends the request method/url/headers. The server responds with a `ByteStream` where # the client can make calls to stream up the request body. `requestBody` will be null in the case # that request.bodySize.fixed == 0. interface ClientRequestContext { # Provides callbacks for the server to send the response. startResponse @0 (response :HttpResponse) -> (body :ByteStream); # Server calls this method to send the response status and headers and to begin streaming the # response body. `body` will be null in the case that response.bodySize.fixed == 0, which is # required for HEAD responses and status codes 204, 205, and 304. startWebSocket @1 (headers :List(HttpHeader), upSocket :WebSocket) -> (downSocket :WebSocket); # Server calls this method to indicate that the request is a valid WebSocket handshake and it # wishes to accept it as a WebSocket. # # Client -> Server WebSocket frames will be sent via method calls on `upSocket`, while # Server -> Client will be sent as calls to `downSocket`. } interface ServerRequestContext { # Represents execution of a particular request on the server side. # # Dropping this object before the request completes will cancel the request. # # ServerRequestContext is always a promise capability. The client must wait for it to # resolve using whenMoreResolved() in order to find out when the server is really done # processing the request. This will throw an exception if the server failed in some way that # could not be captured in the HTTP response. Note that it's possible for such an exception to # be thrown even after the response body has been completely transmitted. } } interface WebSocket { sendText @0 (text :Text) -> stream; sendData @1 (data :Data) -> stream; # Send a text or data frame. close @2 (code :UInt16, reason :Text); # Send a close frame. } struct HttpRequest { # Standard HTTP request metadata. method @0 :HttpMethod; url @1 :Text; headers @2 :List(HttpHeader); bodySize :union { unknown @3 :Void; # e.g. due to transfer-encoding: chunked fixed @4 :UInt64; # e.g. due to content-length } } struct HttpResponse { # Standard HTTP response metadata. statusCode @0 :UInt16; statusText @1 :Text; # leave null if it matches the default for statusCode headers @2 :List(HttpHeader); bodySize :union { unknown @3 :Void; # e.g. due to transfer-encoding: chunked fixed @4 :UInt64; # e.g. due to content-length } } enum HttpMethod { # This enum aligns precisely with the kj::HttpMethod enum. However, the backwards-compat # constraints of a public-facing C++ enum vs. an internal Cap'n Proto interface differ in # several ways, which could possibly lead to divergence someday. For now, a unit test verifies # that they match exactly; if that test ever fails, we'll have to figure out what to do about it. get @0; head @1; post @2; put @3; delete @4; patch @5; purge @6; options @7; trace @8; copy @9; lock @10; mkcol @11; move @12; propfind @13; proppatch @14; search @15; unlock @16; acl @17; report @18; mkactivity @19; checkout @20; merge @21; msearch @22; notify @23; subscribe @24; unsubscribe @25; } annotation commonText @0x857745131db6fc83(enumerant) :Text; enum CommonHeaderName { invalid @0; # Dummy to serve as default value. Should never actually appear on wire. acceptCharset @1 $commonText("Accept-Charset"); acceptEncoding @2 $commonText("Accept-Encoding"); acceptLanguage @3 $commonText("Accept-Language"); acceptRanges @4 $commonText("Accept-Ranges"); accept @5 $commonText("Accept"); accessControlAllowOrigin @6 $commonText("Access-Control-Allow-Origin"); age @7 $commonText("Age"); allow @8 $commonText("Allow"); authorization @9 $commonText("Authorization"); cacheControl @10 $commonText("Cache-Control"); contentDisposition @11 $commonText("Content-Disposition"); contentEncoding @12 $commonText("Content-Encoding"); contentLanguage @13 $commonText("Content-Language"); contentLength @14 $commonText("Content-Length"); contentLocation @15 $commonText("Content-Location"); contentRange @16 $commonText("Content-Range"); contentType @17 $commonText("Content-Type"); cookie @18 $commonText("Cookie"); date @19 $commonText("Date"); etag @20 $commonText("ETag"); expect @21 $commonText("Expect"); expires @22 $commonText("Expires"); from @23 $commonText("From"); host @24 $commonText("Host"); ifMatch @25 $commonText("If-Match"); ifModifiedSince @26 $commonText("If-Modified-Since"); ifNoneMatch @27 $commonText("If-None-Match"); ifRange @28 $commonText("If-Range"); ifUnmodifiedSince @29 $commonText("If-Unmodified-Since"); lastModified @30 $commonText("Last-Modified"); link @31 $commonText("Link"); location @32 $commonText("Location"); maxForwards @33 $commonText("Max-Forwards"); proxyAuthenticate @34 $commonText("Proxy-Authenticate"); proxyAuthorization @35 $commonText("Proxy-Authorization"); range @36 $commonText("Range"); referer @37 $commonText("Referer"); refresh @38 $commonText("Refresh"); retryAfter @39 $commonText("Retry-After"); server @40 $commonText("Server"); setCookie @41 $commonText("Set-Cookie"); strictTransportSecurity @42 $commonText("Strict-Transport-Security"); transferEncoding @43 $commonText("Transfer-Encoding"); userAgent @44 $commonText("User-Agent"); vary @45 $commonText("Vary"); via @46 $commonText("Via"); wwwAuthenticate @47 $commonText("WWW-Authenticate"); } enum CommonHeaderValue { invalid @0; gzipDeflate @1 $commonText("gzip, deflate"); # TODO(someday): "gzip, deflate" is the only common header value recognized by HPACK. } struct HttpHeader { union { common :group { name @0 :CommonHeaderName; union { commonValue @1 :CommonHeaderValue; value @2 :Text; } } uncommon @3 :NameValue; } struct NameValue { name @0 :Text; value @1 :Text; } }