github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/http/handler.go (about) 1 /* For license and copyright information please see LEGAL file in repository */ 2 3 package http 4 5 import ( 6 "../convert" 7 "../log" 8 "../protocol" 9 ) 10 11 type Handler struct{} 12 13 // HandleIncomeRequest handle incoming HTTP request streams. 14 // It can use for architectures like restful, ... 15 // Protocol Standard - HTTP/1 : https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol 16 // Protocol Standard - HTTP/2 : https://httpwg.org/specs/rfc7540.html 17 // Protocol Standard - HTTP/3 : https://quicwg.org/base-drafts/draft-ietf-quic-http.html 18 func (handler *Handler) HandleIncomeRequest(stream protocol.Stream) (err protocol.Error) { 19 var httpReq Request 20 var httpRes Response 21 httpReq.Init() 22 httpRes.Init() 23 var streamSocket = stream.Socket() 24 25 var maybeBody []byte 26 maybeBody, err = httpReq.UnmarshalFrom(streamSocket.Marshal()) 27 if err != nil { 28 httpRes.SetStatus(StatusBadRequestCode, StatusBadRequestPhrase) 29 handler.HandleOutcomeResponse(stream, &httpReq, &httpRes) 30 return 31 } 32 httpReq.body.checkAndSetCodecAsIncomeBody(maybeBody, streamSocket, &httpReq.H) 33 34 err = handler.ServeHTTP(stream, &httpReq, &httpRes) 35 return 36 } 37 38 // ServeHTTP handle incoming HTTP request. 39 // Developers can develope new one with its desire logic to more respect protocols like restful, ... 40 func (handler *Handler) ServeHTTP(stream protocol.Stream, httpReq *Request, httpRes *Response) (err protocol.Error) { 41 if !protocol.AppMode_Dev && !HostSupportedService.ServeHTTP(stream, httpReq, httpRes) { 42 handler.HandleOutcomeResponse(stream, httpReq, httpRes) 43 return 44 } 45 46 switch httpReq.uri.path { 47 case serviceMuxPath: 48 err = MuxService.ServeHTTP(stream, httpReq, httpRes) 49 case landingPath: 50 // TODO::: 51 default: 52 // serve by URL 53 var service protocol.Service 54 service, err = protocol.App.GetServiceByURI(httpReq.uri.path) 55 if service == nil { 56 // If project don't have any logic that support data on e.g. HTTP (restful, ...) we send platform GUI app for web 57 err = ServeWWWService.ServeHTTP(stream, httpReq, httpRes) 58 } else { 59 err = service.ServeHTTP(stream, httpReq, httpRes) 60 } 61 } 62 handler.HandleOutcomeResponse(stream, httpReq, httpRes) 63 return 64 } 65 66 // HandleOutcomeResponse use to handle outcoming HTTP response stream! 67 func (handler *Handler) HandleOutcomeResponse(stream protocol.Stream, httpReq *Request, httpRes *Response) { 68 // Do some global assignment to response 69 httpRes.version = httpReq.version 70 if httpRes.Body() != nil { 71 var mediaType = httpRes.body.MediaType() 72 if mediaType != nil { 73 httpRes.H.Set(HeaderKeyContentType, mediaType.MediaType()) 74 } 75 var compressType = httpRes.body.CompressType() 76 if compressType != nil { 77 httpRes.H.Set(HeaderKeyContentEncoding, compressType.ContentEncoding()) 78 } 79 80 if httpRes.body.Len() > 0 { 81 httpRes.SetContentLength() 82 } else { 83 httpRes.H.SetTransferEncoding(HeaderValueChunked) 84 } 85 } else { 86 httpRes.H.SetZeroContentLength() 87 } 88 89 // httpRes.H.Set(HeaderKeyAccessControlAllowOrigin, "*") 90 91 stream.SendResponse(httpRes) 92 93 if protocol.LogMode_DeepDebug { 94 // TODO::: req||res not serialized yet to log it!! any idea to have better performance below?? 95 protocol.App.Log(log.ConfEvent(domainEnglish, convert.UnsafeByteSliceToString(httpReq.Marshal()))) 96 protocol.App.Log(log.ConfEvent(domainEnglish, convert.UnsafeByteSliceToString(httpRes.Marshal()))) 97 } 98 } 99 100 // SendBidirectionalRequest use to handle outcoming HTTP request stream 101 // It block caller until get response or error 102 func SendBidirectionalRequest(conn protocol.Connection, service protocol.Service, httpReq *Request) (httpRes *Response, err protocol.Error) { 103 var stream protocol.Stream 104 stream, err = conn.OutcomeStream(service) 105 if err != nil { 106 return 107 } 108 109 err = stream.SendRequest(httpReq) 110 if err != nil { 111 return 112 } 113 114 for { 115 var status = <-stream.State() 116 switch status { 117 case protocol.ConnectionState_Timeout: 118 // err = 119 case protocol.ConnectionState_ReceivedCompletely: 120 var res Response 121 res.Init() 122 err = res.Unmarshal(stream.Socket().Marshal()) 123 if err == nil { 124 err = res.GetError() 125 } 126 httpRes = &res 127 default: 128 continue 129 } 130 stream.Close() 131 break 132 } 133 return 134 } 135 136 // SendUnidirectionalRequest use to send outcoming HTTP request and don't expect any response. 137 // It block caller until request send successfully or return error 138 func SendUnidirectionalRequest(conn protocol.Connection, service protocol.Service, httpReq *Request) (err protocol.Error) { 139 var stream protocol.Stream 140 stream, err = conn.OutcomeStream(service) 141 if err != nil { 142 return 143 } 144 145 err = stream.SendRequest(httpReq) 146 if err != nil { 147 return 148 } 149 150 for { 151 var status = <-stream.State() 152 switch status { 153 case protocol.ConnectionState_Timeout: 154 // err = 155 case protocol.ConnectionState_SentCompletely: 156 // Nothing to do. Just let execution go to stream.Close() and break the loop 157 default: 158 continue 159 } 160 stream.Close() 161 break 162 } 163 return 164 }