-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathhttpd.pla
218 lines (211 loc) · 6.49 KB
/
httpd.pla
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
//
// 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
//
include "inc/cmdsys.plh"
include "inc/inet.plh"
include "inc/fileio.plh"
include "inc/conio.plh"
word socketHTTP
byte[65] prefix
word filebuff
byte[15] fileInfo = 0 // used for get_file_info()
byte defhtml = "INDEX.HTML"
byte[200] okhdr // combined response header
//
// 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"
//
// HTTP response headers
//
byte httpContentType = "Content-Type: "
byte httpContentLen = "Content-Length: "
byte httpContentAttach = "Content-Disposition: attachment; filename="
byte httpEnd = "\n\r\n\r"
//
// MIME content types
//
byte mimeTextHtml = "text/html"
byte mimeOctetStream = "application/octet-stream"
//
// DEBUG
//
def putip(ipptr)#0
byte i
for i = 0 to 2
puti(ipptr->[i]); putc('.')
next
puti(ipptr->[i])
end
def dumpbytes(buf, len)#0
word i
for i = 0 to len - 1
putb(buf->[i])
if i & 15 == 15
putln
else
putc(' ')
fin
next
end
def dumpchars(buf, len)#0
word i
len = len - 1
for i = 0 to len
putc(buf->[i])
next
end
//
// String functions
//
def strcat2(dst, src1, src2)
memcpy(dst + 1, src1 + 1, ^src1)
memcpy(dst + 1 + ^src1, src2 + 1, ^src2)
^dst = ^src1 + ^src2
return dst
end
def itos(dst, i)
if i < 0; ^dst = '-'; i = -i; dst++; fin
if i < 10
^dst = i + '0'
else
dst = itos(dst, i / 10)
^dst = i % 10 + '0'
fin
return dst + 1
end
//
// Send the file contents
//
def sendFile(fd, socket, len)#0
while isuge(len, 1024)
fileio:read(fd, filebuff, 1024)
len = len - 1024
iNet:sendTCP(socket, filebuff, 1024)
loop
if len
fileio:read(fd, filebuff, len)
iNet:sendTCP(socket, filebuff, len)
fin
end
//
// Serve HTTP requests
//
def servHTTP(remip, remport, lclport, data, len, param)
byte i, refnum, err
byte[65] filename
byte[8] lenstr
word url, filelen
//
// Parse HTTP request
//
if len > 0
//dumpchars(data, len)
//
// Better be 'GET'
//
if data->0 == 'G' and data->1 == 'E' and data->2 == 'T' and data->3 == ' '
len = len - 1
if len > 64
len = 64 // maximum ProDOS path
fin
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 // Is this a directory with no file given? Use index.html
else
url->1 = url->0 - 1
url = url + 1
fin
fin
strcat2(@filename, @prefix, url)
puts("GET:"); puts(@filename);putln
//
// Get file info
//
//puts("getting file info "); // debug
refnum = fileio:open(@filename) // try to open this file with ProDOS
if refnum // file was opened OK
filelen = fileio:geteof(refnum) // get length of file for Content-Length
lenstr = itos(@lenstr + 1, filelen) - (@lenstr + 1)
strcat2(@okhdr, @httpOK, @httpContentLen)
strcat2(@okhdr, @okhdr, @lenstr)
strcat2(@okhdr, @okhdr, "\n\r")
//
// Content type header
//
fileio:getfileinfo(@filename, @fileInfo)
if fileInfo.1 == $03 OR fileInfo.1 == $04
//
// this a text file
//
//puts(@mimeTextHtml) // debug
strcat2(@okhdr, @okhdr, @httpContentType)
strcat2(@okhdr, @okhdr, @mimeTextHtml)
else
//
// send as binary attachment
//
//puts(@mimeOctetStream) // debug
strcat2(@okhdr, @okhdr, @httpContentType)
strcat2(@okhdr, @okhdr, @mimeOctetStream)
strcat2(@okhdr, @okhdr, "\n\r")
//
// and send filename too
//
strcat2(@okhdr, @okhdr, @httpContentAttach)
// todo: get the base filename...
fin
strcat2(@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
fileio: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 // refnum
break
fin
next
else
iNet:sendTCP(socketHTTP, @httpBAD + 1, httpBAD)
fin
fin
socketHTTP = iNet:closeTCP(socketHTTP)
return 0
end
if !iNet:initIP()
return -1
fin
puts("PLASMA Web Server, Version 1.0\n")
fileio:getpfx(@prefix)
//
// Alloc aligned file/io buffers
//
filebuff = heapallocalign(1024, 8, 0)
//
// Service IP
//
repeat
//
// (Re)Open HTTPD port
//
if !socketHTTP
socketHTTP = iNet:listenTCP(80, @servHTTP, 0)
fin
iNet:serviceIP()
until conio:keypressed()
done