21
21
import Foundation
22
22
import NanoHTTP
23
23
import DynamicJSON
24
+ #if os(iOS) || os(watchOS) || os(tvOS)
25
+ import UIKit
26
+ #elseif os(macOS)
27
+ import Cocoa
28
+ #endif
24
29
25
30
public final class HTTPServerLibrary : NativeLibrary {
26
31
@@ -69,6 +74,7 @@ public final class HTTPServerLibrary: NativeLibrary {
69
74
self . define ( Procedure ( " make-http-server " , self . makeHttpServer) )
70
75
self . define ( Procedure ( " http-server-running? " , self . isHttpServerRunning) )
71
76
self . define ( Procedure ( " http-server-port " , self . httpServerPort) )
77
+ self . define ( Procedure ( " http-server-ipv4 " , self . isHttpServerIPv4) )
72
78
self . define ( Procedure ( " http-server-open-connections " , self . httpServerOpenConnections) )
73
79
self . define ( Procedure ( " http-server-routes " , self . httpServerRoutes) )
74
80
self . define ( Procedure ( " http-server-handlers " , self . httpServerHandlers) )
@@ -107,12 +113,12 @@ public final class HTTPServerLibrary: NativeLibrary {
107
113
self . define ( Procedure ( " srv-request-form-attributes " , self . serverRequestFormAttributes) )
108
114
self . define ( Procedure ( " srv-request-form-multiparts " , self . serverRequestFormMultiparts) )
109
115
self . define ( Procedure ( " srv-request-address " , self . serverRequestAddress) )
110
- self . define ( Procedure ( " srv-request-address " , self . serverRequestAddress) )
111
116
self . define ( Procedure ( " _srv-request-send-response " , self . serverRequestSendResponse) , export: false )
112
117
self . define ( Procedure ( " srv-multipart? " , self . isServerMultipart) )
113
118
self . define ( Procedure ( " srv-multipart-headers " , self . serverMultipartHeaders) )
114
119
self . define ( Procedure ( " srv-multipart-header " , self . serverMultipartHeader) )
115
120
self . define ( Procedure ( " srv-multipart-body " , self . serverMultipartBody) )
121
+ self . define ( Procedure ( " srv-multipart-body->string " , self . serverMultipartBodyToString) )
116
122
self . define ( Procedure ( " srv-response? " , self . isSrvResponse) )
117
123
self . define ( Procedure ( " _make-srv-response " , self . makeSrvResponse) , export: false )
118
124
self . define ( Procedure ( " srv-response-created " , self . srvResponseCreated) )
@@ -377,7 +383,9 @@ public final class HTTPServerLibrary: NativeLibrary {
377
383
private func httpServerRegister( expr: Expr , fst: Expr , snd: Expr , thd: Expr ? ) throws -> Expr {
378
384
if let handler = thd {
379
385
_ = try handler. asProcedure ( )
380
- try self . httpServer ( from: expr) . register ( method: try fst. asString ( ) . uppercased ( ) ,
386
+ try self . httpServer ( from: expr) . register ( method: fst. isFalse
387
+ ? nil
388
+ : try fst. asString ( ) . uppercased ( ) ,
381
389
path: try snd. asString ( ) ,
382
390
handler: handler)
383
391
} else {
@@ -483,17 +491,31 @@ public final class HTTPServerLibrary: NativeLibrary {
483
491
return . makeString( try self . httpServerRequest ( from: expr) . connection. request. path)
484
492
}
485
493
486
- private func serverRequestQuery( expr: Expr ) throws -> Expr {
494
+ private func serverRequestQuery( expr: Expr , inclPath : Expr ? ) throws -> Expr {
487
495
let req = try self . httpServerRequest ( from: expr)
488
496
var components = URLComponents ( )
489
- components. path = req. connection. request. path
490
- if !req. connection. request. queryParams. isEmpty {
497
+ if req. connection. request. queryParams. isEmpty {
498
+ if inclPath? . isTrue ?? false {
499
+ components. path = req. connection. request. path
500
+ } else {
501
+ return . makeString( " " )
502
+ }
503
+ } else {
504
+ if inclPath? . isTrue ?? false {
505
+ components. path = req. connection. request. path
506
+ }
491
507
components. queryItems = req. connection. request. queryParams. map { k, v in
492
508
return URLQueryItem ( name: k. removingPercentEncoding ?? k,
493
509
value: v. removingPercentEncoding ?? v)
494
510
}
495
511
}
496
- return . makeString( components. url? . absoluteString ?? req. connection. request. path)
512
+ if let str = components. string {
513
+ return . makeString( str)
514
+ } else if inclPath? . isTrue ?? false {
515
+ return . makeString( req. connection. request. path)
516
+ } else {
517
+ return . makeString( " " )
518
+ }
497
519
}
498
520
499
521
private func serverRequestPathParam( expr: Expr , name: Expr , default: Expr ? ) throws -> Expr {
@@ -662,6 +684,14 @@ public final class HTTPServerLibrary: NativeLibrary {
662
684
return . bytes( MutableBox ( try self . multiPart ( from: expr) . multipart. body) )
663
685
}
664
686
687
+ private func serverMultipartBodyToString( expr: Expr ) throws -> Expr {
688
+ guard let str = String ( bytes: try self . multiPart ( from: expr) . multipart. body,
689
+ encoding: . utf8) else {
690
+ return . false
691
+ }
692
+ return . makeString( str)
693
+ }
694
+
665
695
// HTTP server response functionality
666
696
667
697
private func isSrvResponse( expr: Expr ) -> Expr {
@@ -770,12 +800,72 @@ public final class HTTPServerLibrary: NativeLibrary {
770
800
return . void
771
801
}
772
802
803
+ #if os(iOS) || os(watchOS) || os(tvOS)
804
+ private func image( _ image: NativeImage , to mimeType: String ) -> Data ? {
805
+ var type : BitmapImageFileType
806
+ switch mimeType {
807
+ case " image/tiff " :
808
+ type = . tiff
809
+ case " image/png " :
810
+ type = . png
811
+ case " image/jpeg " :
812
+ type = . jpeg
813
+ case " image/gif " :
814
+ type = . gif
815
+ case " image/bmp " :
816
+ type = . bmp
817
+ default :
818
+ return nil
819
+ }
820
+ return type. data ( for: image. value)
821
+ }
822
+ #elseif os(macOS)
823
+ private func image( _ image: NativeImage , to mimeType: String ) -> Data ? {
824
+ var type : NSBitmapImageRep . FileType
825
+ switch mimeType {
826
+ case " image/tiff " :
827
+ type = . tiff
828
+ case " image/png " :
829
+ type = . png
830
+ case " image/jpeg " :
831
+ type = . jpeg
832
+ case " image/gif " :
833
+ type = . gif
834
+ case " image/bmp " :
835
+ type = . bmp
836
+ default :
837
+ return nil
838
+ }
839
+ for repr in image. value. representations {
840
+ if let bitmapRepr = repr as? NSBitmapImageRep {
841
+ return bitmapRepr. representation ( using: type, properties: [ : ] )
842
+ }
843
+ }
844
+ return nil
845
+ }
846
+ #endif
847
+
773
848
private func srvResponseBody( from obj: Expr , contentType: Expr ? ) throws -> NanoHTTPResponse . Body {
774
849
switch obj {
775
850
case . false :
776
851
return . empty
777
- case . string( _) :
778
- return . text( try obj. asString ( ) )
852
+ case . string( let str) :
853
+ if let ct = try contentType? . asString ( ) {
854
+ switch ct {
855
+ case " text/plain " :
856
+ return . text( str as String )
857
+ case " text/html " :
858
+ return . html( str as String )
859
+ default :
860
+ if let data = ( str as String ) . data ( using: . utf8) {
861
+ return . data( data, contentType: ct)
862
+ } else {
863
+ return . text( str as String )
864
+ }
865
+ }
866
+ } else {
867
+ return . text( str as String )
868
+ }
779
869
case . bytes( let bv) :
780
870
return . data( Data ( bv. value) , contentType: try contentType? . asString ( ) )
781
871
case . object( let obj) :
@@ -784,15 +874,28 @@ public final class HTTPServerLibrary: NativeLibrary {
784
874
} else if let mutable = obj as? MutableJSON {
785
875
return . json( mutable. value)
786
876
} else if let str = obj as? StyledText {
877
+ if contentType? . isTrue ?? false {
878
+ let data = try str. value. data (
879
+ from: NSMakeRange ( 0 , str. value. length) ,
880
+ documentAttributes: [ . documentType : NSAttributedString . DocumentType. rtf] )
881
+ return . data( data, contentType: " application/rtf " )
882
+ }
787
883
let data = try str. value. data (
788
- from: NSRange ( location: 0 , length: str. value. length) ,
789
- documentAttributes: [ . documentType: NSAttributedString . DocumentType. html,
790
- . characterEncoding: String . Encoding. utf8. rawValue] )
884
+ from: NSRange ( location: 0 , length: str. value. length) ,
885
+ documentAttributes: [ . documentType: NSAttributedString . DocumentType. html,
886
+ . characterEncoding: String . Encoding. utf8. rawValue] )
791
887
if let res = String ( data: data, encoding: String . Encoding. utf8) {
792
888
return . htmlBody( res)
793
889
} else {
794
890
fallthrough
795
891
}
892
+ } else if let image = obj as? NativeImage {
893
+ let ct = try contentType? . asString ( ) ?? " image/png "
894
+ if let data = self . image ( image, to: ct) {
895
+ return . data( data, contentType: ct)
896
+ } else {
897
+ fallthrough
898
+ }
796
899
} else {
797
900
fallthrough
798
901
}
@@ -824,7 +927,8 @@ public final class HTTPServerLibrary: NativeLibrary {
824
927
let name = try name. asString ( ) . lowercased ( )
825
928
var list = expr
826
929
while case . pair( let element, let next) = list {
827
- if case . pair( . string( let str) , let value) = element, ( str as String ) == name {
930
+ if case . pair( . string( let str) , let value) = element,
931
+ ( str as String ) . lowercased ( ) == name {
828
932
return value
829
933
}
830
934
list = next
@@ -851,6 +955,8 @@ public final class HTTPServerLibrary: NativeLibrary {
851
955
}
852
956
current = value. index ( after: current)
853
957
start = current
958
+ } else {
959
+ fallthrough
854
960
}
855
961
default :
856
962
current = value. index ( after: current)
0 commit comments