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