diff --git a/HTTPD.PO b/HTTPD.PO index b1a78a8..93aa551 100644 Binary files a/HTTPD.PO and b/HTTPD.PO differ diff --git a/src/samplesrc/httpd.pla b/src/samplesrc/httpd.pla index 7c983eb..faab0b0 100644 --- a/src/samplesrc/httpd.pla +++ b/src/samplesrc/httpd.pla @@ -1,6 +1,13 @@ // // HTTP Daemon // +// with these updates by D. Finnigan on 12 Nov 15: +// - revised 404 and 400 responses +// - split 200 OK response headers +// - added get_file_info() call +// - check for binary files and set Content-Type accordingly +// still todo: output base filename for Content-Disposition header +// import cmdsys predef syscall, call, getc, gets, putc, puts, putln predef memset, memcpy, modaddr, modexec @@ -32,15 +39,28 @@ word socketHTTP byte[65] prefix byte perr word filebuff, iobuff -byte hello = "Apple II Web Server\n" +byte fileInfo[12] = 0 // used for get_file_info() +byte hello = "Apple II Web Server - 12 Nov 15\n" byte defhtml = "INDEX.HTML" +byte[200] okhdr // combined response header // -// HTTP response +// HTTP response codes +// For the 4xx codes, if you change the body, make sure to update the Content-Length too +byte httpOK = "HTTP/1.1 200 OK\n\r" +byte httpBAD = "HTTP/1.1 400 Bad Request\n\rContent-Type: text/plain\n\rContent-Length: 17\n\r\n\r400 Bad Request\n\r" +byte httpNOTFOUND = "HTTP/1.1 404 Not Found\n\rStatus: 404 Not Found\n\rContent-Type: text/plain\n\rContent-Length: 28\n\r\n\r404 Error: File not found.\n\r" // -byte httpOK = "HTTP/1.1 200 OK\n\rContent-Type: text/html\n\rContent-Length: " +// HTTP response headers +// +byte httpContentType = "Content-Type: " +byte httpContentLen = "Content-Length: " +byte httpContentAttach = "Content-Disposition: attachment; filename=" byte httpEnd = "\n\r\n\r" -byte httpBAD = "HTTP/1.1 404 NOTFOUND\n\rContent-Type: text/plain\n\rContent-Length: 12\n\r\n\rBad Request\n\r" -byte httpNOFILE = "HTTP/1.1 404 NOTFOUND\n\rContent-Type: text/plain\n\rContent-Length: 24\n\r\n\rError:File not found.\n\r" +// +// MIME content types +// +byte mimeTextHtml = "text/html" +byte mimeOctetStream = "application/octet-stream" // // ProDOS routines // @@ -100,6 +120,14 @@ def get_eof(refnum) syscall($D1, @params) return params:2 end +def get_file_info(path) + + fileInfo.0 = 10 // param count + fileInfo:1 = path // path name + + perr = syscall($C4, @fileInfo) + return perr +end // // DEBUG // @@ -186,9 +214,8 @@ end // Serve HTTP requests // def servHTTP(remip, remport, lclport, data, len, param) - byte i, refnum + byte i, refnum, err byte[65] filename - byte[128] okhdr byte[8] lenstr word url, filelen @@ -203,15 +230,15 @@ def servHTTP(remip, remport, lclport, data, len, param) if data->0 == 'G' and data->1 == 'E' and data->2 == 'T' and data->3 == ' ' len = len - 1 if len > 64 - len = 64 + len = 64 // maximum ProDOS path fin - for i = 4 to len + for i = 4 to len // get ProDOS path from URL if data->[i] <= ' ' data->3= i - 4 url = data + 3 if url->1 == '/' if url->0 == 1 - url = @defhtml + url = @defhtml // Is this a directory with no file given? Use index.html else url->1 = url->0 - 1 url = url + 1 @@ -220,19 +247,52 @@ def servHTTP(remip, remport, lclport, data, len, param) strcat(@filename, @prefix, url) putc('G');putc('E');putc('T');putc(':') puts(@filename);putln - refnum = open(@filename, iobuff) - if refnum - filelen = get_eof(refnum) - lenstr = itos(@lenstr + 1, filelen) - (@lenstr + 1) - strcat(@okhdr, @httpOK, @lenstr) - strcat(@okhdr, @okhdr, @httpEnd) - //dumpchars(@okhdr + 1, okhdr) - iNet:sendTCP(socketHTTP, @okhdr + 1, okhdr) - sendFile(refnum, socketHTTP, filelen) - close(refnum) - else - iNet:sendTCP(socketHTTP, @httpNOFILE + 1, httpNOFILE) - fin + + // Get file info + //puts("getting file info "); // debug + get_file_info(@filename) + + + refnum = open(@filename, iobuff) // try to open this file with ProDOS + if refnum // file was opened OK + filelen = get_eof(refnum) // get length of file for Content-Length + lenstr = itos(@lenstr + 1, filelen) - (@lenstr + 1) + strcat(@okhdr, @httpOK, @httpContentLen) + strcat(@okhdr, @okhdr, @lenstr) + strcat(@okhdr, @okhdr, "\n\r") + + // Content type header + // is this a text file? + if fileInfo.4 == $03 OR fileInfo.4 == $04 + //puts(@mimeTextHtml) // debug + strcat(@okhdr, @okhdr, @httpContentType) + strcat(@okhdr, @okhdr, @mimeTextHtml) + + else // send as binary attachment + //puts(@mimeOctetStream) // debug + + strcat(@okhdr, @okhdr, @httpContentType) + strcat(@okhdr, @okhdr, @mimeOctetStream) + strcat(@okhdr, @okhdr, "\n\r") + + // and send filename too + strcat(@okhdr, @okhdr, @httpContentAttach) + + // todo: get the base filename... + + fin + + strcat(@okhdr, @okhdr, @httpEnd) + + //dumpchars(@okhdr + 1, okhdr) // debug + + iNet:sendTCP(socketHTTP, @okhdr + 1, okhdr) // send HTTP response header to client + sendFile(refnum, socketHTTP, filelen) // send file data to client + close(refnum) + else // file couldn't be opened, so return 404 on this + puts("404 Not Found");putln // debug + iNet:sendTCP(socketHTTP, @httpNOTFOUND + 1, httpNOTFOUND) + fin // if refnum return fin next