Check-in [b78d53666f]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Some major changes in the request processing.
Timelines: family | ancestors | descendants | both | HelpServer
Files: files | file ages | folders
SHA1:b78d53666f8e4888809d1ef5b6574a3e9b623a93
User & Date: johnfound 2014-03-18 06:59:24
Context
2014-03-18
08:09
Missed files added. check-in: 09f7282ce8 user: johnfound tags: HelpServer
06:59
Some major changes in the request processing. check-in: b78d53666f user: johnfound tags: HelpServer
2014-03-17
20:58
Implemented rendering of markdown formatted files. Partially... check-in: f370378f5a user: johnfound tags: HelpServer
Changes

Changes to phWeb/phWeb.

cannot compute difference between binary files

Changes to phWeb/phWeb.asm.

94
95
96
97
98
99
100
101
102
103
104
105
106
107
108


; Strings constants

strStartMsg     text  'Starting up server.  Bind to: '
exit_msg        text  'Exiting...', 13, 10

cCRLF           text  13, 10, 0

cDefaultConfig  text  './phWeb.conf'  ; default config file. The command line option can override this.
cDefaultRoot    text  "./"
cDefaultFile    text  "index.html"










|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108


; Strings constants

strStartMsg     text  'Starting up server.  Bind to: '
exit_msg        text  'Exiting...', 13, 10

;cCRLF           text  13, 10, 0

cDefaultConfig  text  './phWeb.conf'  ; default config file. The command line option can override this.
cDefaultRoot    text  "./"
cDefaultFile    text  "index.html"



Changes to phWeb/phWeb.exe.

cannot compute difference between binary files

Changes to phWeb/phWeb.fpr.

cannot compute difference between binary files

Changes to phWeb/requests.asm.

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
219
220
221
222
223
224
225

226
227
228
229
230
231
232
233
234
235

236
237

238
239
240
241
242
243
244


245
246
247
248
249
250
251
252
253



254
255
256
257

258
259
260
261
262
263
264
265
266
267
268
269
270


271
272
273
274
275
276
277


278
279
280
281


282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312

virtual at 0
http_status http_status "1234", "1234", NONE
end virtual


iglobal
  headerHTTP200 http_status 'HTTP/1.1 200 OK', 0, DEFAULT
  headerHTTP400 http_status 'HTTP/1.1 400 Bad request',         '400.html', pageHTTP400

  headerHTTP404 http_status 'HTTP/1.1 404 Not Found',           '404.html', pageHTTP404
  headerHTTP405 http_status 'HTTP/1.1 405 Method Not Allowed',  '405.html', pageHTTP405

  pageHTTP400   file  '400.html'
  .length = $ - pageHTTP400
                dd 0





  pageHTTP404   file  '404.html'
  .length = $-pageHTTP404
                dd 0

  pageHTTP405   file  '405.html'
  .length = $-pageHTTP405
                dd 0



endg



; Process user requests
; arguments:
;   hSocket - the socket handler of the accepted connection.
;   pHeaders - array with strings containing all received headers, including the request line.
proc ProcessRequest, .hSocket, .pHeaders, .pStreamBuffer, .BufferSize, .pStreamPointer
.method   dd ?
.filename dd ?
.query    dd ?
.protocol dd ?

.response dd ?
begin
        pushad

        mov     [.method], 0
        mov     [.filename], 0
        mov     [.query], 0
        mov     [.protocol], 0

        mov     esi, [.pHeaders]
        mov     ecx, [esi+TArray.count]

; Debug code - outputs the headers to the STDERR
if defined options.DebugMode & ~options.DebugMode = 0


.loop:
        dec     ecx
        js      .end_loop
        stdcall FileWriteString, [STDERR], [esi+TArray.array]
        stdcall FileWriteString, [STDERR], cCRLF
        add     esi, 4
        jmp     .loop

.end_loop:
end if
; end debug code.


        mov     esi, [.pHeaders]
        cmp     [esi+TArray.count], 0
        je      .error_400              ; bad request.

        stdcall StrLen, [esi+TArray.array]
        mov     ecx, eax
        stdcall StrPtr, [esi+TArray.array]      ; first string is the http request.
        mov     edi, eax

        cmp     ecx, 4
        jb      .error_400

        mov     eax, [edi]
        lea     edi, [edi+4]
        sub     ecx, 4

        mov     [.method], eax

        mov     al, ' '
        repe scasb

        dec     edi

        cmp    byte [edi], '/'
        jne    @f
        inc    edi
        dec    ecx
@@:
        mov     esi, edi


.end_srch:
        mov     al, [edi]
        cmp     al, ' '
        je      .end_found
        test    al, al
        je      .end_found

        inc     edi
        jmp     .end_srch
.end_found:
        mov     edx, edi
        sub     edx, esi

        stdcall StrDup, [cfgRoot]
        mov     [.filename], eax

        stdcall StrExtract, esi, 0, edx
        mov     ebx, eax

        stdcall StrLen, ebx
        test    eax, eax
        jnz     @f

        stdcall StrCopy, ebx, cDefaultFile
@@:
        stdcall NormalizeFilename, ebx
        jnc     @f
        mov     [.response], headerHTTP404
        stdcall StrDel, ebx
        jmp     .send_header

@@:
        stdcall StrCat, [.filename], ebx

        stdcall StrDel, ebx




        jecxz   .protocol_ok

        stdcall StrExtract, edi, 0, ecx
        mov     [.protocol], eax

.protocol_ok:
        mov     [.response], headerHTTP200

        cmp     [.method], 'GET '
        je      .method_get_head

        cmp     [.method], 'HEAD'
        je      .method_get_head

        mov     [.response], headerHTTP405        ; 405 method not allowed.

.method_get_head:
        stdcall FileExists, [.filename]
        jnc     .send_header
        mov     [.response], headerHTTP404       ; 404 not found

.send_header:
        stdcall SendHeader, [.hSocket], [.response]
        cmp     [.method], 'HEAD'
        je      .finish

        mov     esi, [.response]
        cmp     [esi+http_status.body], -1
        je      .send_file

        cmp     [esi+http_status.body], 0
        je      .finish

        stdcall SocketSend, [.hSocket], [esi+http_status.body], [esi+http_status.bodylen], 0
        jmp     .finish


.send_file:
        stdcall HandlerStatic, [.hSocket], [.filename]

.finish:
        stdcall StrDel, [.filename]
        stdcall StrDel, [.query]
        stdcall StrDel, [.protocol]
        popad
        return

.error_400:
        mov     [.response], headerHTTP400
        jmp     .send_header

endp




headerServer  text  'Server: phWeb', 13, 10
headerStd     text  'Connection: close', 13, 10, \

                    'Cache-Control: no-cache,no-store,max-age=0,must-revalidate', 13, 10, 13, 10


proc SendHeader, .hSocket, .response
begin
        push    eax esi

        mov     esi, [.response]
        stdcall SocketSend, [.hSocket], [esi+http_status.response], [esi+http_status.resplen], 0
        jc      .finish

        stdcall SocketSend, [.hSocket], headerServer, headerServer.length, 0
        jc      .finish

        stdcall SocketSend, [.hSocket], headerStd, headerStd.length, 0
.finish:
        pop     esi eax
        return
endp




;__________________________________________________________________________________
;
; Tryes to remove all "../" directories from the given path.
; If the operation is possible, the result path string will not contains any "../"

proc NormalizeFilename, .hString
begin
        push    eax edx esi edi




        stdcall StrPtr, [.hString]
        mov     esi, eax
        mov     edi, eax


        xor     edx, edx

.loop1:
        mov     eax, [esi]

        and     eax, $ffffff

        cmp     eax, '../'
        je      .back
        cmp     eax, '..\'
        je      .back

        cmp     al, '/'


        je      .dir
        cmp     al, '\'
        je      .dir

        inc     esi
        test    al, al
        jnz     .loop1



        stdcall StrFixLen, [.hString]
        shr     edx, 1
        pop     edi esi edx eax


        return

.dir:
        lea     edi, [esi+1]
        jmp     .loop1

.back:
        cmp     edi, esi
        lea     esi, [esi+3]
        je      .error          ; the path can not be normalized.

        push    edi edi

.copy:
        lodsb
        stosb
        test    al, al
        jnz     .copy

        pop     esi edi
        jmp     .loop1

.error:
        mov     edi, esi
        or      edx, 1
        jmp     .loop1
endp











|

>






>
>
>
>









>
>








|
|
|
|
|
<
<



|
|
|


<
<

|

>
>



|
|




<

>



|







|










<
<
|
|
|
|


>

<
<
<
<
<
<
<
<
<
<


<
<
<
<
<
|

<
|
|
>
|
<
<
<
<
|
|

<
<
>
|
>
>
>







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
<
<
<



|
|


|




<
<
<
<
<




<
<
<
>
|


|

|




>
|

>
|
|
<
<
<

<
>
>
|
|
|
|

<
<
|
<
>
>
>
|
|
<

>
|
<
<
<
<
<
<
<
|
<
<

<
>
>
|
<
<

<
<
<
>
>

<
<
<
>
>

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<





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
219
220
221
222


223

224
225
226
227
228

229
230
231







232


233

234
235
236


237



238
239
240



241
242
243

























244
245
246
247
248

virtual at 0
http_status http_status "1234", "1234", NONE
end virtual


iglobal
  headerHTTP200 http_status 'HTTP/1.1 200 OK',                  0,          NONE
  headerHTTP400 http_status 'HTTP/1.1 400 Bad request',         '400.html', pageHTTP400
  headerHTTP403 http_status 'HTTP/1.1 403 Forbidden',           '403.html', pageHTTP403
  headerHTTP404 http_status 'HTTP/1.1 404 Not Found',           '404.html', pageHTTP404
  headerHTTP405 http_status 'HTTP/1.1 405 Method Not Allowed',  '405.html', pageHTTP405

  pageHTTP400   file  '400.html'
  .length = $ - pageHTTP400
                dd 0

  pageHTTP403   file  '403.html'
  .length = $-pageHTTP403
                dd 0

  pageHTTP404   file  '404.html'
  .length = $-pageHTTP404
                dd 0

  pageHTTP405   file  '405.html'
  .length = $-pageHTTP405
                dd 0

 cCRLF db 13, 10, 0

endg



; Process user requests
; arguments:
;   hSocket - the socket handler of the accepted connection.
;   pHeaders - array with strings containing all received headers, including the request line.
proc ProcessRequest, .hSocket, .pHeaders, .pPostData
  .method    dd ?
  .hCommand  dd ?
  .query     dd ?
  .protocol  dd ?


begin
        pushad

        mov     [.method],   0
        mov     [.hCommand], 0
        mov     [.query],    0
        mov     [.protocol], 0




; Debug code
if defined options.DebugMode & ~options.DebugMode = 0
        mov     esi, [.pHeaders]
        mov     ecx, [esi+TArray.count]
.loop:
        dec     ecx
        js      .end_loop
        stdcall FileWriteString, [STDOUT], [esi+TArray.array]
        stdcall FileWriteString, [STDOUT], cCRLF
        add     esi, 4
        jmp     .loop

.end_loop:

; end debug code.
end if

        mov     esi, [.pHeaders]
        cmp     [esi+TArray.count], 0
        je      .bad_request

        stdcall StrLen, [esi+TArray.array]
        mov     ecx, eax
        stdcall StrPtr, [esi+TArray.array]      ; first string is the http request.
        mov     edi, eax

        cmp     ecx, 4
        jb      .bad_request    ; 400, bad request

        mov     eax, [edi]
        lea     edi, [edi+4]
        sub     ecx, 4

        mov     [.method], eax

        mov     al, ' '
        repe scasb



        cmp     byte [edi], '/'
        jne     @f
        inc     edi
        dec     ecx
@@:
        mov     esi, edi
        repnz scasb











        mov     edx, edi
        sub     edx, esi





        dec     edx


        test    edx, edx
        jnz     .copy_cmd

        stdcall StrNew




        stdcall StrCharCat, eax, 'index.html'
        jmp     .cmd_ok



.copy_cmd:
        stdcall StrExtract, esi, 0, edx

.cmd_ok:
        mov     [.hCommand], eax

        jecxz   .protocol_ok

        stdcall StrExtract, edi, 0, ecx
        mov     [.protocol], eax

.protocol_ok:
        cmp     [.method], 'GET '
        je      .request_ok

        cmp     [.method], 'POST'
        je      .request_ok

        cmp     [.method], 'HEAD'
        je      .head_method

; 405, method not allowed.
        stdcall SendResponse, headerHTTP405
        jmp     .finish

; 400, bad request
.bad_request:
        stdcall SendResponse, headerHTTP400
        jmp     .finish

; 200, OK + HEAD
.head_method:
        stdcall SendResponse, headerHTTP200







        jmp     .finish


.request_ok:
        stdcall ExecuteCommand, [.hSocket], [.hCommand], [.pPostData]

.finish:
        stdcall StrDel, [.hCommand]
        stdcall StrDel, [.query]
        stdcall StrDel, [.protocol]
        popad
        return





endp






hdrServer       text 'Server: Fresh Help server', 13, 10
hdrConnection   text 'Connection: close', 13, 10, 'Cache-Control: no-cache,no-store,max-age=0,must-revalidate', 13, 10


proc SendResponse, .hSocket, .response
begin
        pushad

        mov     esi, [.response]
        stdcall SocketSend, [.hSocket], [esi+http_status.response], [esi+http_status.resplen], 0
        jc      .finish

        stdcall SocketSend, [.hSocket], hdrServer, hdrServer.length, 0
        jc      .finish

        stdcall SocketSend, [.hSocket], hdrConnection, hdrConnection.length, 0
        jc      .finish





.send_body:
        cmp     [esi+http_status.extfile], 0
        je      .try_default

        stdcall LoadBinaryFile, [esi+http_status.extfile]
        jc      .try_default



        push    eax

        stdcall SocketSendStr, [.hSocket], cCRLF
        jc      .finish
        stdcall SocketSend, [.hSocket], eax, ecx, 0
        stdcall FreeMem ; from the stack
        jmp     .finish


.try_default:
        cmp     [esi+http_status.body], 0







        je      .end_ok




        stdcall SocketSendStr, [.hSocket], cCRLF
        stdcall SocketSend, [.hSocket], [esi+http_status.body], [esi+http_status.bodylen], 0
        jc      .finish






.end_ok:
        clc




.finish:
        popad
        return

























endp




Changes to phWeb/sockets.asm.





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
..
66
67
68
69
70
71
72




73
74
75
76
77
78
79
..
86
87
88
89
90
91
92


93
94
95
96
97
98
99
100
101
102
103
...
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
...
207
208
209
210
211
212
213







214







215
216






















217
218
219








220


221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237


























































; This procedure provides the main server loop.
; It listens for connections, accept it and then
; creates a thread that serves the connection.

proc ServerLoop
.addr TSocketAddressIn
.hSocket dd ?
begin


        stdcall SocketCreate, PF_INET, SOCK_STREAM, 0
        jc      .sockerr

        mov     [.hSocket], eax     ; save socket handle





; Bind the socket to the address

; fillup sockaddr
        lea     ecx, [.addr]

        mov     [ecx+TSocketAddressIn.saFamily], AF_INET
        mov     eax, [cfgBindIp]
        mov     edx, [cfgBindPort]
        bswap   eax
        xchg    dl, dh
        mov     [ecx+TSocketAddressIn.saAddress], eax
        mov     [ecx+TSocketAddressIn.saPort], dx

        OutputRegister regEDX, 16

        stdcall  SocketBind, [.hSocket], ecx
        jc       .binderr

; Set the socket to listen for the incomming connections.
.doListen:
        stdcall SocketListen, [.hSocket], 1024
        jc      .listenerr

        DebugMsg "Socket listen OK"
        OutputRegister regEAX, 16

; Accept connection
.doAccept:
        DebugMsg "SocketAccept shoud block now."



        stdcall  SocketAccept, [.hSocket], 0
        jc      .accepterr

        mov     ebx, eax

        DebugMsg "Connection accepted."
        OutputRegister regEBX, 16

        stdcall ThreadCreate, ConnectionHandler, ebx
        jc      .thread_error

        stdcall FreeThreadID, eax

        inc     [ThreadCount]
        jmp     .doAccept
................................................................................
uglobal
  ThreadCount dd ?
endg

; ------------------------------------------------------------

.exit_s:




        stdcall SocketClose, [.hSocket]
        return

; ------------------------------------------------------------

; These are just to print an error message to stderr should
; one of our socket calls fail.
................................................................................
        jmp     .exit_s

.listenerr:
        stdcall FileWriteString, [STDERR], cListensBroke
        jmp     .exit_s

.accepterr:


        stdcall FileWriteString, [STDERR], cAcceptsBroke
;        jmp     .doAccept

        jmp     .exit_s
endp


cSocksBroke   text  'ERROR: SocketCreate failed!', 10
cBindsBroke   text  'ERROR: SocketBind failed!', 10
cListensBroke text  'ERROR: SocketListen failed!', 10
cAcceptsBroke text  'ERROR: SocketAccept failed!', 10
................................................................................
; requests and then calls the request processing procedure.

proc ConnectionHandler, .hSocket
  .buffer   dd ?
  .pHeaders dd ?
  .hCurrent dd ?
  .expect_next dd ?


begin
        pushad



        stdcall StrNew
        mov     [.hCurrent], eax

        stdcall CreateArray, 4
        mov     [.pHeaders], eax

        stdcall GetMem, cStreamBufferSize+4

        mov     [.buffer], eax

.recvloop:
        mov     esi, [.buffer]
        stdcall SocketReceive, [.hSocket], esi, cStreamBufferSize, 0

        test    eax, eax
        jz      .finish         ; the client closed connection.

        mov     ecx, eax
        mov     dword [esi+ecx], 0      ; zero terminator.

        mov     eax, [.expect_next]
................................................................................
        jmp     .outer

.end_of_buffer:         ; concatenate the last (possibly half) line to the hCurrent string.
        stdcall StrCat, [.hCurrent], ebx
        jmp     .recvloop

.end_of_request:        ; there is possibly more content in the buffer (request body)







        mov     edi, [.buffer]







        rep movsb               ; copy the rest of the buffer to the begining of the buffer.























        stdcall ProcessRequest, [.hSocket], [.pHeaders], [.buffer], cStreamBufferSize, edi

.finish:








        stdcall FreeMem,     [.buffer]


        stdcall StrDel,      [.hCurrent]
        stdcall ListFree, [.pHeaders], StrDel
        stdcall SocketClose, [.hSocket]

if defined options.DebugMode & options.DebugMode
        jnc     .end_thread
        DebugMsg "Error close socket."
.end_thread:
        DebugMsg "Socket closed."
end if

        dec     [ThreadCount]
        popad
        return
endp























































>
>
>
>









>
>


<


>
>
>
>













<
<





|


<
<
<


<
>
>






<
<
<







 







>
>
>
>







 







>
>

|
<
<







 







>
>


>
>







|
>





>







 







>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|


>
>
>
>
>
>
>
>

>
>

|


<
<
<
<
<
<
<






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
..
92
93
94
95
96
97
98
99
100
101
102


103
104
105
106
107
108
109
...
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
...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282







283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
uglobal
  fQuit dd ?
endg


; This procedure provides the main server loop.
; It listens for connections, accept it and then
; creates a thread that serves the connection.

proc ServerLoop
.addr TSocketAddressIn
.hSocket dd ?
begin
        mov     [fQuit], 0

        stdcall SocketCreate, PF_INET, SOCK_STREAM, 0
        jc      .sockerr

        mov     [.hSocket], eax     ; save socket handle

        stdcall SocketSetOption, [.hSocket], soReuseAddr, TRUE
        stdcall SocketSetOption, [.hSocket], soRecvTimeout, 3000
        stdcall SocketSetOption, [.hSocket], soSendTimeout, 3000

; Bind the socket to the address

; fillup sockaddr
        lea     ecx, [.addr]

        mov     [ecx+TSocketAddressIn.saFamily], AF_INET
        mov     eax, [cfgBindIp]
        mov     edx, [cfgBindPort]
        bswap   eax
        xchg    dl, dh
        mov     [ecx+TSocketAddressIn.saAddress], eax
        mov     [ecx+TSocketAddressIn.saPort], dx



        stdcall  SocketBind, [.hSocket], ecx
        jc       .binderr

; Set the socket to listen for the incomming connections.
.doListen:
        stdcall SocketListen, [.hSocket], 5
        jc      .listenerr




; Accept connection
.doAccept:

        cmp     [fQuit], 0
        jne     .exit_s

        stdcall  SocketAccept, [.hSocket], 0
        jc      .accepterr

        mov     ebx, eax




        stdcall ThreadCreate, ConnectionHandler, ebx
        jc      .thread_error

        stdcall FreeThreadID, eax

        inc     [ThreadCount]
        jmp     .doAccept
................................................................................
uglobal
  ThreadCount dd ?
endg

; ------------------------------------------------------------

.exit_s:
        stdcall Sleep, 10               ; wait for threads to end...
        cmp     [ThreadCount], 0
        jne     .exit_s

        stdcall SocketClose, [.hSocket]
        return

; ------------------------------------------------------------

; These are just to print an error message to stderr should
; one of our socket calls fail.
................................................................................
        jmp     .exit_s

.listenerr:
        stdcall FileWriteString, [STDERR], cListensBroke
        jmp     .exit_s

.accepterr:
        cmp     eax, serrTimeout
        je      .doAccept
        stdcall FileWriteString, [STDERR], cAcceptsBroke
        jmp     .doAccept


endp


cSocksBroke   text  'ERROR: SocketCreate failed!', 10
cBindsBroke   text  'ERROR: SocketBind failed!', 10
cListensBroke text  'ERROR: SocketListen failed!', 10
cAcceptsBroke text  'ERROR: SocketAccept failed!', 10
................................................................................
; requests and then calls the request processing procedure.

proc ConnectionHandler, .hSocket
  .buffer   dd ?
  .pHeaders dd ?
  .hCurrent dd ?
  .expect_next dd ?

  .post_data dd ?
begin
        pushad

        mov     [.post_data], 0

        stdcall StrNew
        mov     [.hCurrent], eax

        stdcall CreateArray, 4
        mov     [.pHeaders], eax

        stdcall GetMem, cStreamBufferSize+16
        jc      .finish2
        mov     [.buffer], eax

.recvloop:
        mov     esi, [.buffer]
        stdcall SocketReceive, [.hSocket], esi, cStreamBufferSize, 0
        jc      .finish
        test    eax, eax
        jz      .finish         ; the client closed connection.

        mov     ecx, eax
        mov     dword [esi+ecx], 0      ; zero terminator.

        mov     eax, [.expect_next]
................................................................................
        jmp     .outer

.end_of_buffer:         ; concatenate the last (possibly half) line to the hCurrent string.
        stdcall StrCat, [.hCurrent], ebx
        jmp     .recvloop

.end_of_request:        ; there is possibly more content in the buffer (request body)

        stdcall SearchHeaders, [.pHeaders], 'content-length'
        jc      .process_request            ; if not found

        push    eax
        stdcall StrToNumEx, eax
        stdcall StrDel ; from the stack
        mov     edx, eax

        lea     eax, [edx+16]   ; bigger buffer
        stdcall GetMem, eax
        lea     edi, [eax+8]
        mov     [.post_data], edi

        sub     edx, ecx
        rep movsb               ; copy the rest of the buffer to the begining of the post data buffer.

        test    edx, edx
        jz      .end_post
        jns     .post_loop

        xor     edx, edx
        jmp     .end_post

.post_loop:
        stdcall SocketReceive, [.hSocket], edi, edx, 0
        test    eax, eax
        jz      .finish         ; socket has been closed...

        add     edi, eax
        sub     edx, eax
        ja      .post_loop

.end_post:
        mov     dword [edi], 0

        stdcall StrURLDecode,  [.post_data]

.process_request:
        stdcall ProcessRequest, [.hSocket], [.pHeaders], [.post_data]

.finish:
        cmp     [.post_data], 0
        je      .post_ok

        mov     eax, [.post_data]
        sub     eax, 8
        stdcall FreeMem, eax

.post_ok:
        stdcall FreeMem,     [.buffer]

.finish2:
        stdcall StrDel,      [.hCurrent]
        stdcall ListFree,    [.pHeaders], StrDel
        stdcall SocketClose, [.hSocket]








        dec     [ThreadCount]
        popad
        return
endp




proc SearchHeaders, .pHeaders, .pKey
begin
        push    ecx edx esi edi

        mov     edi, [.pHeaders]

        mov     ecx, [edi+TArray.count]

.main_loop:
        dec     ecx
        js      .end_headers

        stdcall StrPtr, [edi+TArray.array+4*ecx]
        mov     esi, eax

        stdcall StrPtr, [.pKey]
        mov     edx, eax

.comp_loop:
        mov     al, [esi]
        mov     ah, [edx]
        lea     esi, [esi+1]
        lea     edx, [edx+1]

        test    al, al
        jz      .main_loop
        test    ah, ah
        jz      .maybe

        or      ax, $2020
        cmp     al, ah
        je      .comp_loop
       jmp      .main_loop

.maybe:
        cmp     al, ':'
        jne     .main_loop

        stdcall StrDup, esi     ; header found, return the value.
        stdcall StrClipSpacesR, eax
        stdcall StrClipSpacesL, eax
        clc
        pop     edi esi edx ecx
        return

.end_headers:
        xor     eax, eax
        stc
        pop     edi esi edx ecx
        return
endp

Changes to phWeb/static.asm.

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
..
54
55
56
57
58
59
60

61
62









63
64
65


































































iglobal
  cMarkdownHeader file 'html_header.inc'
                  dd   0
endg



proc HandlerStatic, .hSocket, .hFileName

  .md_result TMarkdownResults


begin
        pushad

if defined options.DebugMode & options.DebugMode



        stdcall FileWriteString, [STDERR], [.hFileName]
        stdcall FileWriteString, [STDERR], cCRLF
end if












































































        stdcall LoadBinaryFile, [.hFileName]
        jc      .finish2

        mov     esi, eax







; check the file type:

        stdcall StrExtractExt, [.hFileName]
        jc      .finish2



        push    eax
        stdcall StrPtr, eax




        mov     eax, [eax]
        stdcall StrDel ; from the stack


        cmp     eax, '.md'






        jne     .send_static

; markdown formatted file.









        lea     eax, [.md_result]
        stdcall TranslateMarkdown, esi, 0, FALSE, eax

        stdcall SocketSendStr, [.hSocket], cMarkdownHeader
        stdcall SocketSendStr, [.hSocket], [.md_result.hContent]
        stdcall SocketSendStr, [.hSocket], '</body></html>'

        stdcall StrDel, [.md_result.hContent]
        stdcall StrDel, [.md_result.hIndex]
................................................................................
.send_static:
        stdcall SocketSend, [.hSocket], esi, ecx, 0

.free:
        stdcall FreeMem, esi

.finish2:

        popad
        return









endp











































































|


>




<
>
>
>
|
<
<
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>


>
>
>
>
>



|
|

>
>
|
<
>
>
>
>
|
<
>

|
>
>
>
>
>
>
|

<
>
>
>
>
>
>
>
>


|







 







>


>
>
>
>
>
>
>
>
>



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
...
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
iglobal
  cMarkdownHeader file 'html_header.inc'
                  dd   0
endg



proc ExecuteCommand, .hSocket, .hFileName, .ptrPostData

  .md_result TMarkdownResults
  .ext       dd ?

begin
        pushad


        stdcall StrDup, [cfgRoot]
        mov     ebx, eax

        stdcall StrDup, [.hFileName]


        stdcall StrURLDecode, eax
        stdcall StrCat, ebx, eax
        stdcall StrDel, eax


; here, determine the type...

;        int3
;
;        stdcall NormalizeFilename, ebx
;        jc      .error404



        stdcall StrExtractExt, ebx
        jc      .error403
        push    eax

        xor     edx, edx

        stdcall StrPtr, eax
        cmp     [eax+string.len], 3
        jb      .ext_ok
        cmp     [eax+string.len], 5
        ja      .ext_ok

        mov     eax, [eax]
        or      eax, $20202000        ; lower case

        movx    edx, <'Content-type: text/html', 13, 10>

        cmp     eax, '.htm'
        je      .ext_ok

        cmp     eax, '.md '
        je      .ext_ok

        movx    edx, <'Content-type: text/plain', 13, 10>

        cmp     eax, '.txt'
        je      .ext_ok

        movx    edx, <'Content-type: text/css', 13, 10>

        cmp     eax, '.css'
        je      .ext_ok

        movx    edx, <'Content-type: image/png', 13, 10>

        cmp     eax, '.png'
        je      .ext_ok

        movx    edx, <'Content-type: image/svg+xml', 13, 10>

        cmp     eax, '.svg'
        je      .ext_ok

        movx    edx, <'Content-type: image/gif', 13, 10>

        cmp     eax, '.gif'
        je      .ext_ok

        movx    edx, <'Content-type: image/jpeg', 13, 10>

        cmp     eax, '.jpg'
        je      .ext_ok

        xor     edx, edx

.ext_ok:
        stdcall StrDel ; from the stack.
        test    edx, edx
        jz      .error403

        mov     [.ext], eax

        stdcall LoadBinaryFile, ebx
        jc      .error404

        mov     esi, eax

; now send the headers

        stdcall SendResponse, [.hSocket], headerHTTP200
        stdcall SocketSendStr, [.hSocket], edx
        stdcall SocketSendStr, [.hSocket], cCRLF

; check the file type:

        cmp     [.ext], '.md '
        jne     .send_static

; markdown formatted file.

        mov     edx, esi


; search the first cr/lf

.cr_loop:
        mov     al, [edx]

        inc     edx

        cmp     al, $0d
        je      .end_cr
        cmp     al, $0a
        je      .end_cr

        test    al, al
        jnz     .cr_loop
        jmp     .free


.end_cr:
        xor     al, $0d xor $0a
        cmp     [edx], al
        jne     @f
        inc     edx
@@:
        cmp     byte [edx], 0
        je      .free

        lea     eax, [.md_result]
        stdcall TranslateMarkdown, edx, 0, FALSE, eax

        stdcall SocketSendStr, [.hSocket], cMarkdownHeader
        stdcall SocketSendStr, [.hSocket], [.md_result.hContent]
        stdcall SocketSendStr, [.hSocket], '</body></html>'

        stdcall StrDel, [.md_result.hContent]
        stdcall StrDel, [.md_result.hIndex]
................................................................................
.send_static:
        stdcall SocketSend, [.hSocket], esi, ecx, 0

.free:
        stdcall FreeMem, esi

.finish2:
        stdcall StrDel, ebx
        popad
        return

.error404:
        stdcall SendResponse, [.hSocket], headerHTTP404
        jmp     .finish2

.error403:
        stdcall SendResponse, [.hSocket], headerHTTP403
        jmp     .finish2

endp




;__________________________________________________________________________________
;
; Tryes to remove all "../" directories from the given path.
; If the operation is possible, the result path string will not contains any "../"

proc NormalizeFilename, .hString
begin
        push    eax edx esi edi

        stdcall StrPtr, [.hString]
        mov     esi, eax
        mov     edi, eax

        xor     edx, edx

.loop1:
        mov     eax, [esi]

        and     eax, $ffffff

        cmp     eax, '../'
        je      .back
        cmp     eax, '..\'
        je      .back

        cmp     al, '/'
        je      .dir
        cmp     al, '\'
        je      .dir

        inc     esi
        test    al, al
        jnz     .loop1

        stdcall StrFixLen, [.hString]
        shr     edx, 1
        pop     edi esi edx eax
        return

.dir:
        lea     edi, [esi+1]
        jmp     .loop1

.back:
        cmp     edi, esi
        lea     esi, [esi+3]
        je      .error          ; the path can not be normalized.

        push    edi edi

.copy:
        lodsb
        stosb
        test    al, al
        jnz     .copy

        pop     esi edi
        jmp     .loop1

.error:
        mov     edi, esi
        or      edx, 1
        jmp     .loop1
endp