vapor / http Goto Github PK
View Code? Open in Web Editor NEW๐ Non-blocking, event-driven HTTP built on Swift NIO.
License: MIT License
๐ Non-blocking, event-driven HTTP built on Swift NIO.
License: MIT License
I notice that you're percent decoding the URI, but not percent encoding it when constructing a new URI:
https://github.com/vapor/engine/blob/master/Sources/HTTP/Serializer/Serializer%2BURI.swift
Please see vapor/vapor#1101
in V1 it was working with:
let client = try SMTPClient<TCPClientStream>.init(host: host, port: port, securityLayer: SecurityLayer.tls(nil))
try client.send(email, using: credentials)
In V2 I'm trying to send a Mail over SMTP using smpt.zoho.com.
Got the credentials and client conf in a smtpzoho.json file:
{
"client": {
"scheme": "smtps",
"host": "smtp.zoho.eu",
"port": 465
}
let credentials = SMTPCredentials(user: user, pass: pass)
let from = EmailAddress(name: name, address: emailAddress)
let to = EmailAddress(name: name, address: emailAddress)
let emailBody = EmailBody(content: "\(nameRequest) - \(emailRequest) : \(messageRequest)")
let email = Email(from: from,
to: to,
subject: "Contact form \(name)",
body: emailBody)
let portConverted = Port(port)
let mailer = SMTPMailer.init(scheme: scheme, hostname: host, port: portConverted, credentials: credentials)
try mailer.send(email)
Mostly the last two lines have changed, and now a scheme has to be provided. I've tried with several schemes like "ssl", "smtps", ssmtp", "http", "https" but all give me the same error:
[SMTP.SMTPClientError: invalidGreeting(code: -1, greeting: "")]
Conform 'SMTP.SMTPClientError' to Debugging.Debuggable to provide more debug information.
Add an easy API for pinging an open websocket to keep it from timing out.
try ws.ping(every: 10)
try background { [weak ws] in
if ws?.state == .open {
print("ping")
try? ws?.ping()
drop.console.wait(seconds: 10)
}
}
Add a convenience init for TCPServer
that creates a TCPInternetSocket
I am having issues in connecting to a server with an hostname containing _
:
try EngineClientFactory().get("http://test_server-02:8080/my/path")
The problem is in the URIParser
class, which crops the hostname to test
rather than test_server-02
.
Body doesn't take response representable right now. Easy addition.
To workaround the Issue #119 I replaced the Droplet
s default EngineClient with the FoundationClient
like so:
extension FoundationClient: ClientProtocol {
public convenience init(hostname: String, port: Port, _ securityLayer: SecurityLayer) throws {
self.init(scheme: "https", hostname: hostname, port: port)
}
}
drop.client = FoundationClient.self
But I feel like since the FoundationClient
should already conform to this protocol so I can easily interchange the two without having to do this myself.
(Continuing from vapor/vapor#1018.)
#88 incorrectly assumed that the HTTP 307 status is the de facto replacement of the old 302 status code.
Changing the code returned introduced a sneaky breaking behavioral change, making a common use case impossible without dropping down to manually creating redirect responses.
This comes down to a wrong idea: there are not just two kinds of redirects (permanent or temporary).
A very common pattern in web apps is redirecting the browser after a form POST request to a result or list page, which would be loaded using a GET request. (By using this, the chance of duplicated POST requests happening on a page refresh is close to zero.)
In V1, using Response.redirect
in a post handler achieved exactly that.
In V2 with #88 in place, this is not readily available and migrated apps will break.
The industry moved from 302 because the browser's expected behavior was not explicitly defined. The de facto behavior eventually became that the new request uses the GET method โ allowing for the forementioned pattern.
Instead, the status codes 303 and 307 allow for explicit control over the new request. 303 forces the user agent to use GET, and 307 forces it to use the original method again.
These two distinct behaviors, along with 301 โ which is exposed via the permanently
parameter โ are valid choices that should all be available easily.
Manually building the redirect response works:
return Response(status: .seeOther, headers: [.location: "url"])
If you find a bug, please submit a pull request with a failing test case displaying the bug or just create an issue with as much information as possible.
*** Error in `.build/debug/App': corrupted double-linked list: 0x00007f3864027f60 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f387c7827e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x7e6f8)[0x7f387c7896f8]
/lib/x86_64-linux-gnu/libc.so.6(+0x813be)[0x7f387c78c3be]
/lib/x86_64-linux-gnu/libc.so.6(__libc_malloc+0x54)[0x7f387c78e5d4]
/home/xxx/.swiftenv/versions/3.1/usr/lib/swift/linux/libFoundation.so(+0x32a9d4)[0x7f387e2d39d4]
/home/xxx/.swiftenv/versions/3.1/usr/lib/swift/linux/libFoundation.so(CFCharacterSetAddCharactersInString+0x144)[0x7f387e2cdb64]
/home/xxx/.swiftenv/versions/3.1/usr/lib/swift/linux/libFoundation.so(CFCharacterSetCreateWithCharactersInString+0x159)[0x7f387e2cdfc9]
/home/xxx/.swiftenv/versions/3.1/usr/lib/swift/linux/libFoundation.so(+0x36d330)[0x7f387e316330]
/home/xxx/.swiftenv/versions/3.1/usr/lib/swift/linux/libdispatch.so(dispatch_once_f+0x3b)[0x7f387f48c00b]
/home/xxx/.swiftenv/versions/3.1/usr/lib/swift/linux/libFoundation.so(_CFURLComponentsGetURLQueryAllowedCharacterSet+0x2a)[0x7f387e3140fa]
/home/xxx/.swiftenv/versions/3.1/usr/lib/swift/linux/libFoundation.so(_TZFC10Foundation14NSCharacterSetg15urlQueryAllowedVS_12CharacterSet+0xc)[0x7f387e5f329c]
call is coming from Request
at let encoded = q.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
Not really sure what to do about this, since it's probably a swift bug. Does anyone have a reference to a reported bug or a workaround?
The query string that is crashing :
โฟ 5 elements
โฟ 0 : 2 elements
- key : "legal_entity[type]"
- value : "company"
โฟ 1 : 2 elements
- key : "managed"
- value : true
โฟ 2 : 2 elements
- key : "metadata[id]"
- value : "28"
โฟ 3 : 2 elements
- key : "email"
- value : "[email protected]"
โฟ 4 : 2 elements
- key : "country"
- value : "US"
Core initializer throws, makes things difficult that needn't be
Currently, TLS.Config only applies to engine servers and clients. We should attempt to apply these configuration settings to Foundation Stream.
I'm just trying Vapor for the first time today. Xcode 8.1 (not that I think the version matters) pops a deprecation warning for line 27 of Transport/Streams/Socks+Stream.swift. For fear of stepping on someone's toes, I offer this issue here rather than submitting a pull request. Changing the line to read:
try setSendingTimeout(timeval(seconds: timeout))
fixes the problem. I'm happy to submit it as a PR if that helps, but again don't want to step on anyone's toes. Thanks!
I have a simple websocket client that uses Vapor Engine. The client connects to a wss://
endpoint.
The client works fine on macOS.
However, when I compile and run it on Ubuntu, it doesn't connect and I get the following cryptic error:
unsupportedURICharacter(60)
Any ideas what might be the problem?
I'm based in the Czech Republic (UTC+2 now in the summer) and I have Engine tests failing because the date formatters are using specific timestamps, which translate to different dates here. Specifically those are:
Failing because of timezone:
SMTPDateTests.testSMTPDate()
Because of getting different response to google.com
:
SockStreamTests.testTCPInternetSocket()
SockStreamTests.testFoundationStream()
I get: HTTP/1.0 302 Found\r\nCache-Control: private\r\nContent-Type: text/html; charset=UTF-8\r\nLocation: http://www.google.cz/?gfe_rd=cr&ei=WYG8V_CHBtDR8geml7zYAg\r\nContent-Length: 258\r\nDate: Tue, 23 Aug 2016 17:01:13 GMT\r\n\r\n<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n<TITLE>302 Moved</TITLE></HEAD><BODY>\n<H1>302 Moved</H1>\nThe document has moved\n<A HREF=\"http://www.google.cz/?gfe_rd=cr&ei=WYG8V_CHBtDR8geml7zYAg\">here</A>.\r\n</BODY></HTML>\r\n
We just need to find a way to ensure the timezone tests work around the world (probably by setting the timezone in tests to a set one), and pick a different URL than google.com
which responds the same way to all locations.
It appears that the client does not close the stream after it connects.
This is causing servers to be unable to open views or make new connections after a number of client calls.
Updating the TCPClientStream
with a deinit
might fix this:
public final class TCPClientStream: TCPProgramStream, ClientStream {
public func connect() throws -> Stream {
switch securityLayer {
case .none:
try stream.connect()
return stream
case .tls(let provided):
let config: Config
if let c = provided {
config = c
} else {
config = try defaultClientConfig()
}
let secure = try TLS.Socket(config: config, socket: stream)
try secure.connect(servername: host)
return secure
}
}
deinit {
try? stream.close()
}
}
Platform: Ubuntu 16.04
Toolchain: Swift 3.1-DEVELOPMENT-SNAPSHOT-2017-03-13
Engine version: 1.3.11
On Ubuntu 16.04, exchange(requestKey)
consistently removes the third character from the end of the key, causing incorrect invalidSecAcceptHeader
errors.
Correct: 7VcW5v8fw9RuwsCtndDDs+VmQus=
After hashing: 7VcW5v8fw9RuwsCtndDDs+Vmus=
Correct: tlfzFb2mOM86dj/ZWpxF0VCvy6s=
After hashing: tlfzFb2mOM86dj/ZWpxF0VCv6s=
In Vapor/Cookie we are using a hack like "set-cookie": "cookie=42; Path=/\r\nset-cookie:hi=1337"
to work with setting cookies for response serialization.
We need to accept the same format for response parsing. I think this can be achieved with 1 simple rule: if we already have this header key, then append it with /r/nkey:
Once this is done, we'll have full cookie support in Vapor.
Taking over from here vapor/vapor#1055
The check for the 'Upgrade' value in the connection header is case sensitive. I don't know if this is according to the HTTP spec, but various nginx example configurations send the 'upgrade' value in lowercase.
I think this check should be made case insensitive.
Vapor version: 2.0.0-beta.1
Engine version: 2.0.0-beta.1
macOS version: 10.12.4
Swift version: 3.1
Xcode version: 8.3
When using the default droplet client (EngineClient) to make a request that has a large response body, the body will get cut off in the response.
e.g.
let response = try drop.client.get("https://api.github.com/repos/octokit/octokit.rb/releases")
response.json // nil
Upon further investigation dumping the response dump(response)
I get the following:
Response
- HTTP/1.1 200 OK
- Headers:
Access-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
X-GitHub-Media-Type: github.v3; format=json
X-RateLimit-Reset: 1490911130
ETag: "a1fc205783d327be17f7eafbf3f96002"
X-Served-By: eef8b8685a106934dcbb4b7c59fba0bf
Date: Thu, 30 Mar 2017 21:10:37 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 59035
X-Content-Type-Options: nosniff
Status: 200 OK
Link: <https://api.github.com/repositories/417862/releases?page=2>; rel="next", <https://api.github.com/repositories/417862/releases?page=2>; rel="last"
X-GitHub-Request-Id: D6FD:64DE:73E781:93C62B:58DD744D
Cache-Control: public, max-age=60, s-maxage=60
Server: GitHub.com
Vary: Accept-Encoding
Content-Security-Policy: default-src 'none'
X-XSS-Protection: 1; mode=block
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Frame-Options: deny
Access-Control-Allow-Origin: *
- Body:
[{"url":"https://api.github.com/repos/octokit/octokit.rb/releases/4549630","assets_url":"https://api.github.com/repos/octokit/octokit.rb/releases/4549630/assets","upload_url":"https://uploads.github.com/repos/octokit/octokit.rb/releases/4549630/assets{?name,label}","html_url":"https://github.com/octokit/octokit.rb/releases/tag/v4.6.0","id":4549630,"tag_name":"v4.6.0","target_commitish":"master","name":"","draft":false,"author":{"login":"joeyw","id":478247,"avatar_url":"https://avatars1.githubusercontent.com/u/478247?v=3","gravatar_id":"","url":"https://api.github.com/users/joeyw","html_url":"https://github.com/joeyw","followers_url":"https://api.github.com/users/joeyw/followers","following_url":"https://api.github.com/users/joeyw/following{/other_user}","gists_url":"https://api.github.com/users/joeyw/gists{/gist_id}","starred_url":"https://api.github.com/users/joeyw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/joeyw/subscriptions","organizations_url":"https://api.github.com/users/joeyw/orgs","repos_url":"https://api.github.com/users/joeyw/repos","events_url":"https://api.github.com/users/joeyw/events{/privacy}","received_events_url":"https://api.github.com/users/joeyw/received_events","type":"User","site_admin":false},"prerelease":false,"created_at":"2016-11-08T16:22:37Z","published_at":"2016-11-09T08:37:49Z","assets":[],"tarball_url":"https://api.github.com/repos/octokit/octokit.rb/tarball/v4.6.0","zipball_url":"https://api.github.com/repos/octokit/octokit.rb/zipball/v4.6.0","body":"### Library Changes\n\n#829 Sawyer dependency loosened to support new release `'sawyer', '>= 0.5.3', '~> 0.8.0'` Tha
Also trying to parse body.bytes into JSON throws JayError.unexpectedEnd
I was able to get things working by using the FoundationClient
instead:
extension FoundationClient: ClientProtocol {
public convenience init(hostname: String, port: Port, _ securityLayer: SecurityLayer) throws {
self.init(scheme: "https", hostname: hostname, port: port)
}
}
drop.client = FoundationClient.self
let response = try drop.client.get("https://api.github.com/repos/octokit/octokit.rb/releases")
response.json // not nil YAAAAYYYY!!!
Emails using the Gmail client are blocked by default unless you enable access for less-secure apps in your Gmail account settings:
Add back app.json
file (even though it's a little annoying). We no longer use executables, but heroku is still another system that can compile and spit out errors quickly. I think it's useful to know when we've introduced a breaking change on a PR.
When using redirects and the helper function in HTTP/Models/Response/Response.swift:
public convenience init(headers: [HeaderKey: String] = [:], redirect location: String, permanently: Bool = false)
I noticed that the code uses .Found (302). I believe that the industry has moved from using 302 (which was ambiguous in its meeting) to TemporaryRedirect (307).
Can a change be made to change from:
let status: Status = permanently ? .movedPermanently : .found
to:
let status: Status = permanently ? .movedPermanently : .temporaryRedirect
Currently the user is required to change their settings for their Gmail account to "Allow for less secure apps"
fatal error: Error raised at top level: SMTP.SMTPClientError.invalidPassword(534, "5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbtW"): file /Users/buildnode/jenkins/workspace/oss-swift-package-osx/swift/stdlib/public/core/ErrorType.swift, line 160
Both Package.swift file order are not the same, 0.1.0 tag need update to reflect correct Package.swift order.
When sending a PUT request to a Node.js REST service on my local machine that takes on average 700ms to 1s to resolve, the Vapor application fails the client request almost immediately before the request even touches the starting breakpoint of the Node.js route handler. I've only seen this issue occur when using the Vapor Engine 2.0.3 as the client framework; when the framework is switched to Foundation the error disappeared completely and the REST request would resolve normally.
I've tracked the issue down to a specific block of code in the HTTP+Client.swift
file of the Vapor Engine 2.0.3 package. From what I can tell the stream sends the bytes to the Node.js REST service on line 69 of my screenshot below but attempts to read from the stream too quickly on line 88 despite the fact that my service hasn't completed its operation yet. As a result, the read
constant is set to 0 and the response stream appears to be empty which triggers the guard to break the while loop; causing the empty Response object to throw the StreamError.closed
error.
When a breakpoint is set on line 81 of the screenshot below and the client request is made, the breakpoint is hit and execution is blocked for roughly 2-3 seconds before I allow the program to continue execution. Given the brief pause, my Node.js service is able to complete it's operation and the stream can successfully read the response from my service. As a result the read
constant is now set to 2048 instead and the Response object is successfully initialized.
String's conformance to HTTPResponseRepresentable
should set the text/plain
content type.
This will get rid of this error in Vapor:
Response had no 'Content-Type' header.
HTTP Client currently has a hard-coded User-Agent.
While User-Agents should not be used as some sort of security mechanism, some API's/services may treat a client differently when it is not what they expect. I'm not aware of any other HTTP clients that do not allow you to modify your User-Agent.
Let the existing Vapor client User-Agent be the default value if one is not provided to the client like other headers.
There should be no impact as long as the current User-Agent is still provided as a default.
We encounter an openssl error that kill all sockets when a second web socket client connect to our server:
Transport Layer Security Error: 123145522679880:error:140C5042:SSL routines:ssl_undefined_function:called a function you should not call:ssl_lib.c:2799:
The server is initialized as follow:
let publicCert = Bundle.main.path(forResource: "publicCert", ofType: "pem")!
let privateKey = Bundle.main.path(forResource: "privateKey", ofType: "pem")!
self.tlsContext = try! TLS.Context(
.server,
.files(
certificateFile: publicCert,
privateKeyFile: privateKey,
signature: .selfSigned
),
verifyHost: true,
verifyCertificates: false
)
let tcp = try TCPInternetSocket(scheme: "https", hostname:"127.0.0.1", port: port)
let tls = TLS.InternetSocket(tcp, self.tlsContext)
let server = try TLSServer(tls, listenMax: 128)
And we upgrade to a web socket as follow:
func respond(to request: Request) throws -> Response {
return try request.upgradeToWebSocket { ws in
....
}
}
If we use a Async server, the server crashed in AsyncServerWorker.swift
at line 36
:
readSource.setEventHandler {
try! self.onDataAvailable(client)
}
I'd like to print out a full URI object, or use it as a string. Currently I can't without an extension. URI should store the original string used to create it, or be able to output its representation in a way.
While i tried to connect to the Websocket of the Poloniex https://poloniex.com/support/api/ i encountered response properties with a mix of lowercase/uppercase styles. The WebSocket+Client.swift implementation checks against "upgrade" with "websocket" while Poloniex responded with "WebSocket".
To solve this problem i lowercased the response properties in the header check.
Pullrequest: #61
Take the following server with a security layer config launched on macOS:
let tlsConfig = try TLS.Config(
mode: .server,
certificates: .files(
certificateFile: publicCert,
privateKeyFile: privateKey,
signature: .selfSigned
),
verifyHost: true,
verifyCertificates: true
)
self.server = try Server<TCPServerStream, Parser<Request>, Serializer<Response>>(
host:"127.0.0.1",
port: port,
securityLayer: SecurityLayer.tls(self.tlsConfig)
)
When I start with the synchronous method start
, the handshake with the client is done without any issue. But if I start the server with the asynchronous method startAsync
, the handshake fails. By digging into LibreSSL I found that the handshake fails with the following error SSL_ERROR_WANT_READ
=> TLS_WANT_POLLIN
.
The server currently takes 3 generic arguments to be created, but client only takes 1. Is it possible to have them both take 3?
Grand Central Dispatch is spawning a limited amount of threads (my tests indicated number of virtual CPU cores * 5
, but at minimum 64
).
Since Server
responds to requests on a GCD queue, the server stalls if that pool is exhausted. New requests get queued but may wait for processing forever โ for example if all threads are waiting for data on sockets that are not connected anymore (there is currently no read timeout set on server sockets).
When running behind nginx, this is irrelevant as long as the connection between nginx and Vapor is good.
When exposed directly, the server stalls within minutes or hours.
I think it's reasonable to only process 64 parallel requests; however, waiting on (potentially dead) sockets shouldn't happen in this queue. A read timeout on the socket would help, but not solve the problem.
In the end, the socket should be non-blocking. Unfortunately, I currently don't see an easy way to get there.
Come up with a good way to get the peerAddress from a proxy, for example, Nginx uses the X-Forwarded-For header.
On the README:
import Engine
let response = try HTTPClient<TCPClientStream>.get("http://pokeapi.co/api/v2/pokemon/")
print(response)
In the example:
import HTTP
import Transport
let response = try Client<TCPClientStream>.get("http://pokeapi.co/api/v2/pokemon/")
print(response)
Something like
User-Agent: Vapor Engine/0.4.1
Message-Id
header generated by NSUUID.smtpMessageId does not conform to RFC 2822 3.6.4.
The header should look like Message-Id: <id-left@id-right>
, but it looks like Message-Id: some-id
.
Example of a proper header:
Message-Id: <[email protected]>
Example of a malformed Vapor header:
Message-Id: 96A48F682B3B46C28A3F208C9BD4F356
Example of a Vapor header automatically fixed by Gmail during delivery:
Message-Id: <[email protected]>
I have noticed this issue because any emails sent using Vapor SMTP get an INVALID_MSGID penalty from SpamAssassin.
Conform to RFC by appending @hostname
and adding angular brackets to the message ID. The current host name can be retrieved using gethostname
function as seen here. I can create a pull request with appropriate changes, but I'm not sure how to properly attribute a relevant code snippet from Swift repo.
Actual Message ID value is not used within Vapor, so the change will not affect anything except SMTPUUIDTests.swift
Add helpers for setting authentication headers (Basic, Bearer)
Eliminate the need for making Authentication Header strings from scratch when unit testing or doing outbound requests.
Extend Request with something like this:
func setBasicAuth(username: String, password: String) {
let encoded = "\(username):\(password)".makeBytes().base64Encoded.makeString()
headers[.authorization] = "Basic \(encoded)"
}
func setBearerAuth(token: String) {
headers[.authorization] = "Bearer \(token)"
}
func testUserRegister() throws {
let username = "testUserRegister_username"
let password = "testUserRegister_password"
let req = Request(method: .post, uri: "/user/register/")
req.setBasicAuth(username: username, password: password)
_ = try drop.respond(to: req)
let user = try User.first(with: [("username", username)])
XCTAssertNotNil(user, "user not registered")
}
Other classes/protocols in other modules could be modified to similar effect, like Credentials in Authentication with Password and Token conforming.
req[.authorization] = password.makeAuthString()
If agreed, i can make a pull request.
As per the HTTP 2.0 spec, header names should be lowercased. Currently all headers in Vapor's HeaderKey
class are CamelCase.
Whilst Vapor does not currently support HTTP 2.0, if run behind Nginx or something that does, headers may be forwarded and will be invalid, so they should be made lowercase. In HTTP 1 header keys are case-insensitive so this won't introduce any issues.
(You could argue it is the responsibility of the proxy to lowercase everything but better to be safe!)
When building with Xcode 8.2 and running the Vapor WebClient (under XCTest) communicating with the WebServer under Vapor (running using startServers() to run it in the background), I get an Error: Array out of bounds error.
I have tracked it down to the code:
let combination = requestKey.bytes.trimmed([.space]).array + hashKey
Apparently, this generates an [Byte] and the next line of code then crashes. Changing this to create a Data instance from the [Byte] allows the Hash code to call the ByteRepresentable code that allocates a new block and avoids this error.
The new line then reads:
let combination = Data(requestKey.bytes.trimmed([.space]).array + hashKey)
Must send emojis ๐ช๐ป
Query parameters are not included in the requests when uri doesn't have any.
client.request(.get, "http://localhost", query: ["key": "value"])
Expected Behaviour:
["key": "value"]
.Current Behaviour:
nil
.Code involved:
Responder+Helpers.swift
public func request(
_ method: Method,
_ uri: String,
query: [String: NodeRepresentable] = [:],
_ headers: [HeaderKey: String] = [:],
_ body: BodyRepresentable? = nil,
through middleware: [Middleware] = []
) throws -> Response {
let uri = try URI(uri)
let req = Request(method: method, uri: uri)
req.headers = headers
for (key, value) in query {
try req.query?.set(key, value)
}
if let body = body {
req.body = body.makeBody()
}
return try respond(to: req, through: middleware)
}
Note:
This works if the uri contains already a query parameter (for example: client.request(.get, "http://localhost?foo=bar", query: ["key": "value"])
), because of the Request
extension in:
Request+FormURLEncoded.swift
public var query: Node?
When running the vapor image in an Ubuntu 14.04 Docker image w/ the Swift 3.0.2 RELEASE toolchain, and error "Illegal Instruction" gets thrown when trying to create the SMTP client.
let client = try SMTPClient<TCPClientStream>.makeGmailClient()
The packages installed in the Docker images are:
build-essential wget clang-3.6 curl libedit-dev python2.7 python2.7-dev libicu52 rsync libxml2 git
I have an API with a URI like this:
let uri = "http://vapor.com/api/users/P%2BXCW4asdfa%2FOljlkH90/image?size=small&color=blue"
I then call:
let result = drop.client.get(uri)
Vapor then calls URIParser.parse(...) to decode the URI including the path:
https://github.com/vapor/engine/blob/master/Sources/URI/Parser/Parser.swift#L66
Unfortunately, Vapor will decode, then re-encode the ENTIRE path.
In this case, when it decodes and re-encodes the path component (in Request.swift), "P%2BXCW4asdfa%2FOljlkH90"
gets "malformed" and creates/interprets it as a new path component:ย "P+XCW4asdfa/OljlkH90"
.
The correct solution is for Vapor to faithfully reproduce my original URL, but I think Vapor is trying to be "correct" and build a "model" of what my URL looks like. But it's not accommodating for percent encoding in the URL path.
There is a /github on the URL for the repo description that I am guessing should be /engine
It'd be great if the HTTP.Method initializer that takes a String would be made public. Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.