github.com/rafael-santiago/cherry@v0.0.0-20161214151746-8ea42c6e9670/src/pkg/rawhttp/rawhttp.go (about) 1 /* 2 Package rawhttp implements conveniences related with HTTP request/reply operations. 3 -- 4 * 5 * Copyright (C) 2015 by Rafael Santiago 6 * 7 * This is a free software. You can redistribute it and/or modify under 8 * the terms of the GNU General Public License version 2. 9 * 10 */ 11 package rawhttp 12 13 import ( 14 "fmt" 15 "io/ioutil" 16 "net/url" 17 "strings" 18 ) 19 20 var charLT map[string]string 21 var charLTInitialized bool 22 23 func initCharLT() { 24 charLT = make(map[string]string) 25 charLT["%E2%82%AC"] = "%80" 26 charLT["%E2%80%9A"] = "%82" 27 charLT["%C6%92"] = "%83" 28 charLT["%E2%80%9E"] = "%84" 29 charLT["%E2%80%A6"] = "%85" 30 charLT["%E2%80%A0"] = "%86" 31 charLT["%E2%80%A1"] = "%87" 32 charLT["%CB%86"] = "%88" 33 charLT["%E2%80%B0"] = "%89" 34 charLT["%C5%A0"] = "%8A" 35 charLT["%E2%80%B9"] = "%8B" 36 charLT["%C5%92"] = "%8C" 37 charLT["%C5%8D"] = "%8D" 38 charLT["%C5%BD"] = "%8E" 39 charLT["%C2%90"] = "%90" 40 charLT["%E2%%80%98"] = "%91" 41 charLT["%E2%80%99"] = "%92" 42 charLT["%E2%80%9C"] = "%93" 43 charLT["%E2%80%9D"] = "%94" 44 charLT["%E2%80%A2"] = "%95" 45 charLT["%E2%80%93"] = "%96" 46 charLT["%E2%80%94"] = "%97" 47 charLT["%CB%9C"] = "%98" 48 charLT["%E2%84"] = "%99" 49 charLT["%C5%A1"] = "%9A" 50 charLT["%E2%80"] = "%9B" 51 charLT["%C5%93"] = "%9C" 52 charLT["%C5%BE"] = "%9E" 53 charLT["%C5%B8"] = "%9F" 54 charLT["%C2%A0"] = "%A0" 55 charLT["%C2%A1"] = "%A1" 56 charLT["%C2%A2"] = "%A2" 57 charLT["%C2%A3"] = "%A3" 58 charLT["%C2%A4"] = "%A4" 59 charLT["%C2%A5"] = "%A5" 60 charLT["%C2%A6"] = "%A6" 61 charLT["%C2%A7"] = "%A7" 62 charLT["%C2%A8"] = "%A8" 63 charLT["%C2%A9"] = "%A9" 64 charLT["%C2%AA"] = "%AA" 65 charLT["%C2%AB"] = "%AB" 66 charLT["%C2%AC"] = "%AC" 67 charLT["%C2%AD"] = "%AD" 68 charLT["%C2%AE"] = "%AE" 69 charLT["%C2%AF"] = "%AF" 70 charLT["%C2%B0"] = "%B0" 71 charLT["%C2%B1"] = "%B1" 72 charLT["%C2%B2"] = "%B2" 73 charLT["%C2%B3"] = "%B3" 74 charLT["%C2%B4"] = "%B4" 75 charLT["%C2%B5"] = "%B5" 76 charLT["%C2%B6"] = "%B6" 77 charLT["%C2%B7"] = "%B7" 78 charLT["%C2%B8"] = "%B8" 79 charLT["%C2%B9"] = "%B9" 80 charLT["%C2%BA"] = "%BA" 81 charLT["%C2%BB"] = "%BB" 82 charLT["%C2%BC"] = "%BC" 83 charLT["%C2%BD"] = "%BD" 84 charLT["%C2%BE"] = "%BE" 85 charLT["%C2%BF"] = "%BF" 86 charLT["%C3%80"] = "%C0" 87 charLT["%C3%81"] = "%C1" 88 charLT["%C3%82"] = "%C2" 89 charLT["%C3%83"] = "%C3" 90 charLT["%C3%84"] = "%C4" 91 charLT["%C3%85"] = "%C5" 92 charLT["%C3%86"] = "%C6" 93 charLT["%C3%87"] = "%C7" 94 charLT["%C3%88"] = "%C8" 95 charLT["%C3%89"] = "%C9" 96 charLT["%C3%8A"] = "%CA" 97 charLT["%C3%8B"] = "%CB" 98 charLT["%C3%8C"] = "%CC" 99 charLT["%C3%8D"] = "%CD" 100 charLT["%C3%8E"] = "%CE" 101 charLT["%C3%8F"] = "%CF" 102 charLT["%C3%90"] = "%D0" 103 charLT["%C3%91"] = "%D1" 104 charLT["%C3%92"] = "%D2" 105 charLT["%C3%93"] = "%D3" 106 charLT["%C3%94"] = "%D4" 107 charLT["%C3%95"] = "%D5" 108 charLT["%C3%96"] = "%D6" 109 charLT["%C3%97"] = "%D7" 110 charLT["%C3%98"] = "%D8" 111 charLT["%C3%99"] = "%D9" 112 charLT["%C3%9A"] = "%DA" 113 charLT["%C3%9B"] = "%DB" 114 charLT["%C3%9C"] = "%DC" 115 charLT["%C3%9D"] = "%DD" 116 charLT["%C3%9E"] = "%DE" 117 charLT["%C3%9F"] = "%DF" 118 charLT["%C3%A0"] = "%E0" 119 charLT["%C3%A1"] = "%E1" 120 charLT["%C3%A2"] = "%E2" 121 charLT["%C3%A3"] = "%E3" 122 charLT["%C3%A4"] = "%E4" 123 charLT["%C3%A5"] = "%E5" 124 charLT["%C3%A6"] = "%E6" 125 charLT["%C3%A7"] = "%E7" 126 charLT["%C3%A8"] = "%E8" 127 charLT["%C3%A9"] = "%E9" 128 charLT["%C3%AA"] = "%EA" 129 charLT["%C3%AB"] = "%EB" 130 charLT["%C3%AC"] = "%EC" 131 charLT["%C3%AD"] = "%ED" 132 charLT["%C3%AE"] = "%EE" 133 charLT["%C3%AF"] = "%EF" 134 charLT["%C3%B0"] = "%F0" 135 charLT["%C3%B1"] = "%F1" 136 charLT["%C3%B2"] = "%F2" 137 charLT["%C3%B3"] = "%F3" 138 charLT["%C3%B4"] = "%F4" 139 charLT["%C3%B5"] = "%F5" 140 charLT["%C3%B6"] = "%F6" 141 charLT["%C3%B7"] = "%F7" 142 charLT["%C3%B8"] = "%F8" 143 charLT["%C3%B9"] = "%F9" 144 charLT["%C3%BA"] = "%FA" 145 charLT["%C3%BB"] = "%FB" 146 charLT["%C3%BC"] = "%FC" 147 charLT["%C3%BD"] = "%FD" 148 charLT["%C3%BE"] = "%FE" 149 charLT["%C3%BF"] = "%FF" 150 charLTInitialized = true 151 } 152 153 func cherryDefaultHTTPReplyHeader(statusCode int, closeConnection bool) string { 154 var header = "HTTP/1.1 " 155 switch statusCode { 156 case 200: 157 header += "200 OK" 158 break 159 160 case 404: 161 header += "404 NOT FOUND" 162 break 163 164 case 403: 165 header += "403 FORBIDDEN" 166 break 167 168 default: 169 header += "501 NOT IMPLEMENTED" 170 break 171 } 172 if closeConnection { 173 header += "\n\rConnection: close\n" + 174 "Server: Cherry/0.1\n" + 175 "Accept-ranges: bytes\n" + 176 "Content-type: text/html\n" + 177 "Content-length: {{.content-length}}\n\n" 178 } else { 179 header += "200 Document follows\nContent-type: text/html\n\n" 180 } 181 return header 182 } 183 184 // MakeReplyBuffer assembles the reply buffer based on the statusCode. 185 func MakeReplyBuffer(buffer string, statusCode int, closeConnection bool) []byte { 186 return []byte(strings.Replace(cherryDefaultHTTPReplyHeader(statusCode, closeConnection)+buffer, 187 "{{.content-length}}", 188 fmt.Sprintf("%d", len(buffer)), 189 -1)) 190 } 191 192 // MakeReplyBufferByFilePath assembles the reply buffer base on the file data and the statusCode. 193 func MakeReplyBufferByFilePath(filePath string, statusCode int, closeConnection bool) []byte { 194 buffer, err := ioutil.ReadFile(filePath) 195 if err != nil { 196 return []byte("") 197 } 198 tempReply := strings.Replace(cherryDefaultHTTPReplyHeader(statusCode, closeConnection)+string(buffer), 199 "{{.content-length}}", 200 fmt.Sprintf("%d", len(buffer)), 201 -1) 202 tempReply = strings.Replace(tempReply, "Content-type: text/html", getContentTypeFromFilePath(filePath), -1) 203 return []byte(tempReply) 204 } 205 206 func getContentTypeFromFilePath(filePath string) string { 207 if strings.HasSuffix(filePath, ".gif") { 208 return "Content-type: image/gif" 209 } 210 if strings.HasSuffix(filePath, ".jpeg") || strings.HasSuffix(filePath, ".jpg") { 211 return "Content-type: image/jpeg" 212 } 213 if strings.HasSuffix(filePath, ".png") { 214 return "Content-type: image/png" 215 } 216 if strings.HasSuffix(filePath, ".bmp") { 217 return "Content-type: image/bmp" 218 } 219 return "Content-type: text/plain" 220 } 221 222 // GetHTTPFieldFromBuffer returns data carried by some HTTP field inside a HTTP request. 223 func GetHTTPFieldFromBuffer(field, buffer string) string { 224 index := strings.Index(buffer, field+":") 225 if index == -1 { 226 return "" 227 } 228 retval := "" 229 if len(buffer) > index+len(field) { 230 for _, b := range buffer[index+len(field+":"):] { 231 if b == '\n' || b == '\r' { 232 break 233 } 234 if len(retval) == 0 && (b == ' ' || b == '\t') { 235 continue 236 } 237 retval += string(b) 238 } 239 } 240 return retval 241 } 242 243 func utf8Unescape(data string) string { 244 if !charLTInitialized { 245 initCharLT() 246 } 247 var buffer = data 248 for k, v := range charLT { 249 buffer = strings.Replace(buffer, k, v, -1) 250 } 251 finalData, _ := url.QueryUnescape(buffer) 252 return finalData 253 } 254 255 func splitFields(buffer string) map[string]string { 256 dataValue := strings.Split(buffer, "&") 257 retval := make(map[string]string) 258 for _, dv := range dataValue { 259 set := strings.Split(dv, "=") 260 if len(set) == 2 { 261 retval[set[0]] = utf8Unescape(set[1]) 262 } 263 } 264 return retval 265 } 266 267 // GetFieldsFromPost returns a map containing all fields in a HTTP post. 268 func GetFieldsFromPost(buffer string) map[string]string { 269 if !strings.HasPrefix(buffer, "POST /") { 270 return make(map[string]string) 271 } 272 index := strings.Index(buffer, "\r\n\r\n") 273 if index == -1 || len(buffer) <= index+4 { 274 return make(map[string]string) 275 } 276 return splitFields(buffer[index+4:]) 277 } 278 279 // GetFieldsFromGet returns a map containing all fields in a HTTP get. 280 func GetFieldsFromGet(buffer string) map[string]string { 281 if !strings.HasPrefix(buffer, "GET /") { 282 return make(map[string]string) 283 } 284 var startIndex int 285 var endIndex int 286 for buffer[startIndex] != '&' { 287 startIndex++ 288 } 289 for buffer[endIndex] != '\n' && buffer[endIndex] != '\r' && endIndex < len(buffer) { 290 endIndex++ 291 } 292 return splitFields(buffer[startIndex+1 : endIndex]) 293 }