Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ let package = Package(
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "2.0.0-beta"),
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"),
.package(url: "https://github.com/swift-extras/swift-extras-base64.git", from: "1.0.0"),
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.9.0"),
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.15.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0"),
],
targets: [
Expand Down
7 changes: 2 additions & 5 deletions Sources/HummingbirdLambda/APIGatewayLambda.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,16 @@ where Responder.Context: InitializableFromSource<LambdaRequestContextSource<APIG
// conform `APIGatewayRequest` to `APIRequest` so we can use Request.init(context:application:from)
extension APIGatewayRequest: APIRequest {
var queryString: String {
func urlPercentEncoded(_ string: String) -> String {
return string.addingPercentEncoding(withAllowedCharacters: .urlQueryComponentAllowed) ?? string
}
var queryParams: [String] = []
var queryStringParameters = self.queryStringParameters
// go through list of multi value query string params first, removing any
// from the single value list if they are found in the multi value list
for (key, value) in self.multiValueQueryStringParameters {
queryStringParameters[key] = nil
queryParams += value.map { "\(urlPercentEncoded(key))=\(urlPercentEncoded($0))" }
queryParams += value.map { "\(key.addingPercentEncoding(forURLComponent: .query))=\($0.addingPercentEncoding(forURLComponent: .query))" }
}
queryParams += queryStringParameters.map {
"\(urlPercentEncoded($0.key))=\(urlPercentEncoded($0.value))"
"\($0.key.addingPercentEncoding(forURLComponent: .query))=\($0.value.addingPercentEncoding(forURLComponent: .query))"
}
return queryParams.joined(separator: "&")
}
Expand Down
17 changes: 0 additions & 17 deletions Sources/HummingbirdLambda/Request+APIGateway.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import AWSLambdaEvents
import AWSLambdaRuntime
import ExtrasBase64
import Foundation
import HTTPTypes
import Hummingbird
import NIOCore
Expand All @@ -32,10 +31,6 @@ protocol APIRequest: LambdaEvent {

extension APIRequest {
public func request(context: LambdaContext) throws -> Request {
func urlPercentEncoded(_ string: String) -> String {
string.addingPercentEncoding(withAllowedCharacters: .urlQueryComponentAllowed) ?? string
}

// construct URI with query parameters
var uri = self.path
if self.queryString.count > 0 {
Expand Down Expand Up @@ -74,10 +69,6 @@ extension APIRequest {
extension Request {
/// Specialization of Lambda.request where `In` is `APIGateway.Request`
init(context: LambdaContext, from: some APIRequest) throws {
func urlPercentEncoded(_ string: String) -> String {
string.addingPercentEncoding(withAllowedCharacters: .urlQueryComponentAllowed) ?? string
}

// construct URI with query parameters
var uri = from.path
if from.queryString.count > 0 {
Expand Down Expand Up @@ -135,11 +126,3 @@ extension HTTPFields {
}
}
}

extension CharacterSet {
nonisolated(unsafe) static var urlQueryComponentAllowed: CharacterSet = {
var cs = CharacterSet.urlQueryAllowed
cs.remove(charactersIn: "&=")
return cs
}()
}
176 changes: 176 additions & 0 deletions Sources/HummingbirdLambda/Utils/OutputBuffer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Hummingbird server framework project
//
// Copyright (c) 2021-2022 the Hummingbird authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Licenses out of date


struct OutputBuffer<T>: ~Copyable // ~Escapable
{
let start: UnsafeMutablePointer<T>
let capacity: Int
var initialized: Int = 0

deinit {
// `self` always borrows memory, and it shouldn't have gotten here.
// Failing to use `relinquishBorrowedMemory()` is an error.
if initialized > 0 {
fatalError()
}
}

// precondition: pointer points to uninitialized memory for count elements
init(initializing: UnsafeMutablePointer<T>, capacity: Int) {
start = initializing
self.capacity = capacity
}
}

extension OutputBuffer {
mutating func appendElement(_ value: T) {
precondition(initialized < capacity, "Output buffer overflow")
start.advanced(by: initialized).initialize(to: value)
initialized &+= 1
}

mutating func deinitializeLastElement() -> T? {
guard initialized > 0 else { return nil }
initialized &-= 1
return start.advanced(by: initialized).move()
}
}

extension OutputBuffer {
mutating func deinitialize() {
let b = UnsafeMutableBufferPointer(start: start, count: initialized)
b.deinitialize()
initialized = 0
}
}

extension OutputBuffer {
mutating func append<S>(
from elements: S
) -> S.Iterator where S: Sequence, S.Element == T {
var iterator = elements.makeIterator()
append(from: &iterator)
return iterator
}

mutating func append(
from elements: inout some IteratorProtocol<T>
) {
while initialized < capacity {
guard let element = elements.next() else { break }
start.advanced(by: initialized).initialize(to: element)
initialized &+= 1
}
}

mutating func append(
fromContentsOf source: some Collection<T>
) {
let count = source.withContiguousStorageIfAvailable {
guard let sourceAddress = $0.baseAddress, !$0.isEmpty else {
return 0
}
let available = capacity &- initialized
precondition(
$0.count <= available,
"buffer cannot contain every element from source."
)
let tail = start.advanced(by: initialized)
tail.initialize(from: sourceAddress, count: $0.count)
return $0.count
}
if let count {
initialized &+= count
return
}

let available = capacity &- initialized
let tail = start.advanced(by: initialized)
let suffix = UnsafeMutableBufferPointer(start: tail, count: available)
var (iterator, copied) = source._copyContents(initializing: suffix)
precondition(
iterator.next() == nil,
"buffer cannot contain every element from source."
)
assert(initialized + copied <= capacity)
initialized &+= copied
}

mutating func moveAppend(
fromContentsOf source: UnsafeMutableBufferPointer<T>
) {
guard let sourceAddress = source.baseAddress, !source.isEmpty else {
return
}
let available = capacity &- initialized
precondition(
source.count <= available,
"buffer cannot contain every element from source."
)
let tail = start.advanced(by: initialized)
tail.moveInitialize(from: sourceAddress, count: source.count)
initialized &+= source.count
}

mutating func moveAppend(
fromContentsOf source: Slice<UnsafeMutableBufferPointer<T>>
) {
moveAppend(fromContentsOf: UnsafeMutableBufferPointer(rebasing: source))
}
}

extension OutputBuffer<UInt8> /* where T: BitwiseCopyable */ {

mutating func appendBytes<Value /*: BitwiseCopyable */>(
of value: borrowing Value,
as: Value.Type
) {
precondition(_isPOD(Value.self))
let (q, r) = MemoryLayout<Value>.stride.quotientAndRemainder(
dividingBy: MemoryLayout<T>.stride
)
precondition(
r == 0,
"Stride of Value must be divisible by stride of Element"
)
precondition(
(capacity &- initialized) >= q,
"buffer cannot contain every byte of value."
)
let p = UnsafeMutableRawPointer(start.advanced(by: initialized))
p.storeBytes(of: value, as: Value.self)
initialized &+= q
}
}

extension OutputBuffer {
consuming func relinquishBorrowedMemory() -> UnsafeMutableBufferPointer<T> {
let start = self.start
let initialized = self.initialized
discard self
return .init(start: start, count: initialized)
}
}
Loading