@@ -17,32 +17,11 @@ extension HTTP
17
17
public
18
18
protocol Server : Sendable
19
19
{
20
- associatedtype StreamedRequest : HTTP . ServerStreamedRequest
21
-
22
20
/// Checks whether the server should allow the request to proceed with an upload.
23
21
/// Returns nil if the server should accept the upload, or an error response to send
24
- /// if the uploader lacks permissions.
25
- func clearance( for request: StreamedRequest ) async throws -> HTTP . ServerResponse ?
26
-
27
- func response( for request: StreamedRequest ,
28
- with body: __owned [ UInt8 ] ) async throws -> HTTP . ServerResponse
29
-
30
- func get(
31
- request: ServerRequest ,
32
- headers: HPACKHeaders ) async throws -> HTTP . ServerResponse
33
- func get(
34
- request: ServerRequest ,
35
- headers: HTTPHeaders ) async throws -> HTTP . ServerResponse
36
-
37
- func post(
38
- request: ServerRequest ,
39
- headers: HPACKHeaders ,
40
- body: [ UInt8 ] ) async throws -> HTTP . ServerResponse
41
-
42
- func post(
43
- request: ServerRequest ,
44
- headers: HTTPHeaders ,
45
- body: [ UInt8 ] ) async throws -> HTTP . ServerResponse
22
+ /// if the uploader lacks permissions. This is only called for `PUT` requests.
23
+ func reject( request: ServerRequest ) async throws -> ServerResponse ?
24
+ func accept( request: ServerRequest , method: ServerMethod ) async throws -> ServerResponse
46
25
47
26
func log( event: ServerEvent , ip origin: ServerRequest . Origin ? )
48
27
@@ -51,33 +30,6 @@ extension HTTP
51
30
}
52
31
extension HTTP . Server
53
32
{
54
- /// Inefficiently converts the headers to equivalent HPACK headers, and calls the witness
55
- /// for ``get(request:headers:) [4VK5G]``.
56
- ///
57
- /// Servers that expect to handle a lot of HTTP/1.1 GET requests should override this with
58
- /// a more efficient implementation.
59
- @inlinable public
60
- func get(
61
- request: HTTP . ServerRequest ,
62
- headers: HTTPHeaders ) async throws -> HTTP . ServerResponse
63
- {
64
- try await self . get ( request: request, headers: . init( httpHeaders: headers) )
65
- }
66
-
67
- /// Inefficiently converts the headers to equivalent HPACK headers, and calls the witness
68
- /// for ``post(request:headers:body:) [541MX]``.
69
- ///
70
- /// Servers that expect to handle a lot of HTTP/1.1 POST requests should override this with
71
- /// a more efficient implementation.
72
- @inlinable public
73
- func post(
74
- request: HTTP . ServerRequest ,
75
- headers: HTTPHeaders ,
76
- body: [ UInt8 ] ) async throws -> HTTP . ServerResponse
77
- {
78
- try await self . post ( request: request, headers: . init( httpHeaders: headers) , body: body)
79
- }
80
-
81
33
/// Dumps detailed information about the caught error. This information will be shown to
82
34
/// *anyone* accessing the server. In production, we strongly recommend overriding this
83
35
/// default implementation to avoid inadvertently exposing sensitive data via type
@@ -401,17 +353,22 @@ extension HTTP.Server
401
353
return . resource( " Malformed URI \n " , status: 400 )
402
354
}
403
355
356
+ let request : HTTP . ServerRequest = . init( headers: . http1_1( h1. headers) ,
357
+ origin: origin,
358
+ uri: uri)
359
+
404
360
switch h1. method
405
361
{
406
- case . HEAD :
407
- fallthrough
362
+ case . DELETE :
363
+ return try await self . accept ( request : request , method : . delete )
408
364
409
365
case . GET:
410
- return try await self . get (
411
- request: . init( origin: origin, uri: uri) ,
412
- headers: h1. headers)
366
+ return try await self . accept ( request: request, method: . get)
413
367
414
- case . PUT:
368
+ case . HEAD:
369
+ return try await self . accept ( request: request, method: . head)
370
+
371
+ case . POST:
415
372
guard
416
373
let length: String = h1. headers [ " content-length " ] . first,
417
374
let length: Int = . init( length)
@@ -420,28 +377,21 @@ extension HTTP.Server
420
377
return . resource( " Content length required \n " , status: 411 )
421
378
}
422
379
423
- guard
424
- let request: StreamedRequest = . init( put: uri, headers: h1. headers)
425
- else
426
- {
427
- return . resource( " Malformed request \n " , status: 400 )
428
- }
429
-
430
- if let failure: HTTP . ServerResponse = try await self . clearance ( for: request)
380
+ if length > 1_000_000
431
381
{
432
- return failure
382
+ return . resource ( " Content too large \n " , status : 413 )
433
383
}
434
384
435
385
guard
436
386
let body: [ UInt8 ] = try await inbound. accumulateBuffers ( length: length)
437
387
else
438
388
{
439
- return . resource( " Content length does not match payload \n " , status: 413 )
389
+ return . resource( " Content length does not match payload \n " , status: 400 )
440
390
}
441
391
442
- return try await self. response ( for : request, with : body)
392
+ return try await self . accept ( request : request, method : . post ( body) )
443
393
444
- case . POST :
394
+ case . PUT :
445
395
guard
446
396
let length: String = h1. headers [ " content-length " ] . first,
447
397
let length: Int = . init( length)
@@ -450,22 +400,19 @@ extension HTTP.Server
450
400
return . resource( " Content length required \n " , status: 411 )
451
401
}
452
402
453
- if length > 1_000_000
403
+ if let failure : HTTP . ServerResponse = try await self . reject ( request : request )
454
404
{
455
- return . resource ( " Content too large \n " , status : 413 )
405
+ return failure
456
406
}
457
407
458
408
guard
459
409
let body: [ UInt8] = try await inbound. accumulateBuffers ( length: length)
460
410
else
461
411
{
462
- return . resource( " Content length does not match payload \n " , status: 400 )
412
+ return . resource( " Content length does not match payload \n " , status: 413 )
463
413
}
464
414
465
- return try await self . post (
466
- request: . init( origin: origin, uri: uri) ,
467
- headers: h1. headers,
468
- body: body)
415
+ return try await self. accept ( request: request, method: . put( body) )
469
416
470
417
default:
471
418
return . resource ( " Method requires HTTP/2 \n " , status: 505 )
@@ -656,64 +603,20 @@ extension HTTP.Server
656
603
return . resource( " Malformed URI " , status: 400 )
657
604
}
658
605
606
+ let request : HTTP . ServerRequest = . init( headers: . http2( headers) ,
607
+ origin: origin,
608
+ uri: path)
609
+
659
610
switch method
660
611
{
661
- case " HEAD " :
662
- // return .resource("Method not allowed", status: 405)
663
- fallthrough
612
+ case " DELETE " :
613
+ return try await self . accept ( request: request, method: . delete)
664
614
665
615
case " GET " :
666
- return try await self . get (
667
- request: . init( origin: origin, uri: path) ,
668
- headers: headers)
669
-
670
- case " PUT " :
671
- guard
672
- let length: String = headers [ " content-length " ] . first,
673
- let length: Int = . init( length)
674
- else
675
- {
676
- return . resource( " Content length required " , status: 411 )
677
- }
616
+ return try await self . accept ( request: request, method: . get)
678
617
679
- guard
680
- let request: StreamedRequest = . init( put: path, headers: headers)
681
- else
682
- {
683
- return . resource( " Malformed request " , status: 400 )
684
- }
685
-
686
- if let failure: HTTP . ServerResponse = try await self . clearance ( for: request)
687
- {
688
- return failure
689
- }
690
-
691
- var body: [ UInt8] = [ ]
692
- body. reserveCapacity ( length)
693
-
694
- while let payload: HTTP2 Frame. FramePayload? = try await inbound. next ( )
695
- {
696
- // We could care less about timeout events here, as we have already determined
697
- // the request originates from a trusted source.
698
- guard case . data( let payload) ? = payload
699
- else
700
- {
701
- continue
702
- }
703
-
704
- if case . byteBuffer( let payload) = payload. data
705
- {
706
- payload. withUnsafeReadableBytes { body += $0 }
707
- }
708
-
709
- // Why can’t NIO do this for us?
710
- if payload. endStream
711
- {
712
- break
713
- }
714
- }
715
-
716
- return try await self. response ( for: request, with: body)
618
+ case " HEAD " :
619
+ return try await self . accept ( request: request, method: . head)
717
620
718
621
case " POST " :
719
622
guard
@@ -768,13 +671,51 @@ extension HTTP.Server
768
671
}
769
672
}
770
673
771
- return try await self.post(
772
- request: .init(origin: origin, uri: path),
773
- headers: headers,
774
- body: body)
674
+ return try await self. accept ( request: request, method: . post( body) )
675
+
676
+ case " PUT" :
677
+ guard
678
+ let length: String = headers [ " content-length " ] . first,
679
+ let length: Int = . init( length)
680
+ else
681
+ {
682
+ return . resource( " Content length required " , status: 411 )
683
+ }
684
+
685
+ if let failure: HTTP . ServerResponse = try await self . reject ( request: request)
686
+ {
687
+ return failure
688
+ }
689
+
690
+ var body: [ UInt8] = [ ]
691
+ body. reserveCapacity ( length)
692
+
693
+ while let payload: HTTP2 Frame. FramePayload? = try await inbound. next ( )
694
+ {
695
+ // We could care less about timeout events here, as we have already determined
696
+ // the request originates from a trusted source.
697
+ guard case . data( let payload) ? = payload
698
+ else
699
+ {
700
+ continue
701
+ }
702
+
703
+ if case . byteBuffer( let payload) = payload. data
704
+ {
705
+ payload. withUnsafeReadableBytes { body += $0 }
706
+ }
707
+
708
+ // Why can’t NIO do this for us?
709
+ if payload. endStream
710
+ {
711
+ break
712
+ }
713
+ }
714
+
715
+ return try await self. accept ( request: request, method: . put( body) )
775
716
776
717
case _:
777
- return .forbidden( " Forbidden " )
718
+ return . resource ( " Method not allowed \n " , status : 405 )
778
719
}
779
720
}
780
721
}
0 commit comments