Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env io
- urlEscapes := Map with("%20", " ", "%3C", "<", "%3E", ">", "%23", "#", "%25", "%", "%7B", "{", "%7D", "}", "%7C", "|", "%5C", "\\", "%5E", "^", "%7E", "~", "%5B", "[", "%5D", "]", "%60", "`", "%3B", ";", "%2F", "/", "%3F", "?", "%3A", ":", "%40", "@", "%3D", "=", "%26", "&", "%24", "$")
- Sequence unescapeURL := method(
- replaceMap(urlEscapes)
- )
- mimeTypes := Map with("html", "text/html", "txt", "text/plain", "io", "text/plain")
- Sequence corespondingMIMEType := method(
- mimeTypes at(self)
- )
- WebRequest := Object clone do(
- cache := Map clone
- handleSocket := method(socket, server,
- socket streamReadNextChunk
- if(socket isOpen == false, return)
- buf := socket readBuffer
- closeConnection := buf betweenSeq("Connection: ", "\n") == "close"
- if (buf betweenSeq("Host: ", "\n") == nil,
- stream streamWrite(responseHeader(400, "Bad Request", "text/html", nil, true) .. noHostMessage)
- return
- )
- request := buf betweenSeq("GET ", " HTTP") asMutable
- if (request == nil, return)
- if(request beginsWithSeq("/"), request lstrip("/"))
- if(request size == 0, request appendPathSeq("."))
- request unescapeURL
- cacheItem := cache atIfAbsentPut(request,
- writeln("caching ", request)
- file := File with(request)
- if (file exists,
- // check if request is a directory, if so append index.html and build an index
- // cache items are lists, first is the data, then number of times requested
- if(file isDirectory,
- indexData := generateIndexForPath(request)
- request appendPathSeq("index.html")
- if (indexData, list(indexData, 0), nil)
- ,
- list(file contents, 0))
- ,
- nil)
- )
- closeConnection = true // persistent connections are not working yet
- if(cacheItem, okResponse(cacheItem, request, closeConnection), notFoundResponse(request)) foreach(part,
- socket streamWrite(part))
- if (closeConnection or(cacheItem not),
- socket close
- )
- )
- generateIndexForPath := method(dirPath,
- basePath := Directory currentWorkingDirectory .. "/"
- dirPath = if(dirPath not or(dirPath size == 0), basePath, basePath cloneAppendPath(dirPath))
- dir := Directory with(dirPath)
- heading := "Index of " .. dir path afterSeq(basePath)
- html := "<html><body><h2>#{heading}</h2><br><ul>" asMutable interpolateInPlace
- if (dir isAccessible,
- dir items foreach(item,
- if (item name beginsWithSeq(".") not,
- html appendSeq("<li><a href=\"#{item path afterSeq(basePath)}\">#{item name}</a>" interpolate)
- )
- )
- )
- html appendSeq("</ul></body></html>")
- )
- okResponse := method(cacheItem, request, closeConnection,
- data := cacheItem first
- cacheItem push(cacheItem pop + 1)
- range := call sender buf betweenSeq("Range: bytes=", "\n")
- data = if(range, byteRange(range, data), data)
- list(responseHeader(200, "OK", mimeTypeForFile(request), data size,closeConnection), data)
- )
- mimeTypeForFile := method(fileName,
- fileName pathExtension corespondingMIMEType
- )
- byteRange := method(range, data,
- ranges := range split("-")
- if (ranges size == 0, return "")
- data inclusiveSlice(ranges first asNumber, if(ranges size == 2, ranges last asNumber, data size))
- )
- notFoundResponse := method(request,
- list(responseHeader(404, "Not Found", "text/html", nil, true), "<html><body><h2>Not Found</h2>#{request} was not found.</body></html>" interpolate)
- )
- responseHeader := method(code, reason, contentType, length, close,
- "HTTP/1.1 #{code asString} #{reason}\r\nDate: #{formattedDate}" interpolate .. if(contentType, "\r\nContent-Type: " .. contentType, "") .. if(length, "\r\nContent-Length: " .. length asString, "") .. if(close, "\r\nConnection: close", "") .. "\r\n\n"
- )
- formattedDate := method(
- Date clone now convertToUTC asString("%a, %d %b %Y %H:%M:%S %Z")
- )
- noHostMessage := "<html><body><h2>No Host: header received</h2>HTTP 1.1 requests must include the Host: header.</body></html>"
- checkCache := method(
- if (cache size > 100,
- // remove least commonly requested items
- cache foreach(k, v,
- if (v last < 4, cache removeAt(k))
- )
- )
- )
- )
- /*FileChunk := Object clone do(
- chunkForFile := method(file, startByte, length,
- chunk := clone
- chunk buffer := file clone setPosition(startBytes) futureSend(readStringOfLength(length))
- chunk asString := buffer
- chunk
- )
- )*/
- WebServer := Server clone do(
- setPort(7777)
- socket setHost("127.0.0.1")
- reqCount := 0
- handleSocket := method(socket,
- WebRequest clone @handleSocket(socket, self)
- reqCount = reqCount + 1
- if (reqCount > 250, WebRequest checkCache; reqCount = 0)
- )
- ) start
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement