Subversion Repositories Kolibri OS

Rev

Rev 4222 | Rev 4241 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4158 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  HTTP library for KolibriOS                                     ;;
7
;;                                                                 ;;
8
;;   Written by hidnplayr@kolibrios.org                            ;;
4233 hidnplayr 9
;;   Proxy code written by CleverMouse                             ;;
4158 hidnplayr 10
;;                                                                 ;;
11
;;         GNU GENERAL PUBLIC LICENSE                              ;;
12
;;          Version 2, June 1991                                   ;;
13
;;                                                                 ;;
14
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
15
 
16
; references:
17
; "HTTP made really easy", http://www.jmarshall.com/easy/http/
18
; "Hypertext Transfer Protocol -- HTTP/1.1", http://tools.ietf.org/html/rfc2616
19
 
20
 
21
        URLMAXLEN       = 65535
22
        BUFFERSIZE      = 4096
4206 hidnplayr 23
        TIMEOUT         = 1000  ; in 1/100 s
4158 hidnplayr 24
 
25
        __DEBUG__       = 1
26
        __DEBUG_LEVEL__ = 1
27
 
28
 
29
format MS COFF
30
 
31
public @EXPORT as 'EXPORTS'
32
 
33
include '../../../struct.inc'
34
include '../../../proc32.inc'
35
include '../../../macros.inc'
36
purge section,mov,add,sub
37
include '../../../debug-fdo.inc'
38
 
39
include '../../../network.inc'
40
include 'http.inc'
41
 
42
virtual at 0
43
        http_msg http_msg
44
end virtual
45
 
46
macro copy_till_zero {
47
  @@:
48
        lodsb
49
        test    al, al
50
        jz      @f
51
        stosb
52
        jmp     @r
53
  @@:
54
}
55
 
4167 hidnplayr 56
macro HTTP_init_buffer buffer, socketnum {
57
 
58
        mov     eax, buffer
59
        push    socketnum
60
        popd    [eax + http_msg.socket]
61
        lea     esi, [eax + http_msg.data]
4205 hidnplayr 62
        mov     [eax + http_msg.flags], FLAG_CONNECTED
4167 hidnplayr 63
        mov     [eax + http_msg.write_ptr], esi
64
        mov     [eax + http_msg.buffer_length], BUFFERSIZE -  http_msg.data
65
        mov     [eax + http_msg.chunk_ptr], 0
66
 
67
        mov     [eax + http_msg.status], 0
68
        mov     [eax + http_msg.header_length], 0
69
        mov     [eax + http_msg.content_length], 0
4168 hidnplayr 70
        mov     [eax + http_msg.content_received], 0
4206 hidnplayr 71
 
72
        push    eax ebp
73
        mov     ebp, eax
74
        mcall   29, 9
75
        mov     [ebp + http_msg.timestamp], eax
76
        pop     ebp eax
4167 hidnplayr 77
}
78
 
4158 hidnplayr 79
section '.flat' code readable align 16
80
 
81
;;===========================================================================;;
82
lib_init: ;//////////////////////////////////////////////////////////////////;;
83
;;---------------------------------------------------------------------------;;
84
;? Library entry point (called after library load)                           ;;
85
;;---------------------------------------------------------------------------;;
86
;> eax = pointer to memory allocation routine                                ;;
87
;> ebx = pointer to memory freeing routine                                   ;;
88
;> ecx = pointer to memory reallocation routine                              ;;
89
;> edx = pointer to library loading routine                                  ;;
90
;;---------------------------------------------------------------------------;;
4209 hidnplayr 91
;< eax = 1 (fail) / 0 (ok)                                                   ;;
4158 hidnplayr 92
;;===========================================================================;;
93
        mov     [mem.alloc], eax
94
        mov     [mem.free], ebx
95
        mov     [mem.realloc], ecx
96
        mov     [dll.load], edx
97
 
98
        invoke  dll.load, @IMPORT
4209 hidnplayr 99
        test    eax, eax
100
        jnz     .error
4158 hidnplayr 101
 
102
; load proxy settings
4216 hidnplayr 103
        pusha
4158 hidnplayr 104
        invoke  ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr
105
        invoke  ini.get_int, inifile, sec_proxy, key_proxyport, 80
106
        mov     [proxyPort], eax
107
        invoke  ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser
108
        invoke  ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword
4216 hidnplayr 109
        popa
4158 hidnplayr 110
 
4212 hidnplayr 111
        DEBUGF  1, "HTTP library: init OK\n"
4211 hidnplayr 112
 
4158 hidnplayr 113
        xor     eax, eax
114
        ret
115
 
4209 hidnplayr 116
  .error:
4212 hidnplayr 117
        DEBUGF  1, "ERROR loading libraries\n"
4211 hidnplayr 118
 
4158 hidnplayr 119
        xor     eax, eax
4209 hidnplayr 120
        inc     eax
121
 
4158 hidnplayr 122
        ret
123
 
124
 
125
 
126
 
127
;;================================================================================================;;
4221 hidnplayr 128
proc HTTP_get URL, add_header ;///////////////////////////////////////////////////////////////////;;
4158 hidnplayr 129
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 130
;? Initiates a HTTP connection, using 'GET' method.                                               ;;
4158 hidnplayr 131
;;------------------------------------------------------------------------------------------------;;
4221 hidnplayr 132
;> URL          = pointer to ASCIIZ URL                                                           ;;
133
;> add_header   = pointer to additional header parameters (ASCIIZ), or null for none.             ;;
4158 hidnplayr 134
;;------------------------------------------------------------------------------------------------;;
135
;< eax = 0 (error) / buffer ptr                                                                   ;;
136
;;================================================================================================;;
137
locals
138
        hostname        dd ?
139
        pageaddr        dd ?
140
        sockaddr        dd ?
141
        socketnum       dd ?
142
        buffer          dd ?
4167 hidnplayr 143
        port            dd ?
4158 hidnplayr 144
endl
145
 
4216 hidnplayr 146
        pusha
147
 
4158 hidnplayr 148
; split the URL into hostname and pageaddr
149
        stdcall parse_url, [URL]
150
        test    eax, eax
151
        jz      .error
152
        mov     [hostname], eax
153
        mov     [pageaddr], ebx
4221 hidnplayr 154
        mov     [port], ecx
4158 hidnplayr 155
 
4167 hidnplayr 156
; Connect to the other side.
157
        stdcall open_connection, [hostname], [port]
4158 hidnplayr 158
        test    eax, eax
4167 hidnplayr 159
        jz      .error
160
        mov     [socketnum], eax
4158 hidnplayr 161
 
4167 hidnplayr 162
; Create the HTTP request.
163
        invoke  mem.alloc, BUFFERSIZE
4158 hidnplayr 164
        test    eax, eax
165
        jz      .error
4167 hidnplayr 166
        mov     [buffer], eax
167
        mov     edi, eax
168
        DEBUGF  1, "Buffer has been allocated.\n"
4158 hidnplayr 169
 
4167 hidnplayr 170
        mov     esi, str_get
171
        copy_till_zero
4158 hidnplayr 172
 
4233 hidnplayr 173
; If we are using a proxy, send complete URL, otherwise send only page address.
174
        cmp     [proxyAddr], 0
175
        je      .no_proxy
176
        mov     esi, str_http           ; prepend 'http://'
177
        copy_till_zero
178
        mov     esi, [hostname]
179
        copy_till_zero
180
  .no_proxy:
4167 hidnplayr 181
        mov     esi, [pageaddr]
182
        copy_till_zero
4158 hidnplayr 183
 
4167 hidnplayr 184
        mov     esi, str_http11
185
        mov     ecx, str_http11.length
186
        rep     movsb
187
 
188
        mov     esi, [hostname]
189
        copy_till_zero
190
 
4221 hidnplayr 191
        mov     esi, [add_header]
192
        test    esi, esi
193
        jz      @f
194
        copy_till_zero
195
  @@:
196
 
4233 hidnplayr 197
        cmp     byte[proxyUser], 0
198
        je      @f
199
        call    append_proxy_auth_header
200
  @@:
201
 
4167 hidnplayr 202
        mov     esi, str_close
203
        mov     ecx, str_close.length
204
        rep     movsb
205
 
206
        mov     byte[edi], 0
207
        DEBUGF  1, "Request:\n%s", [buffer]
208
 
4222 hidnplayr 209
; Free unused memory
210
        push    edi
211
        invoke  mem.free, [pageaddr]
212
        invoke  mem.free, [hostname]
213
        pop     esi
214
 
4167 hidnplayr 215
; Send the request
216
        sub     esi, [buffer]   ; length
217
        xor     edi, edi        ; flags
218
        mcall   send, [socketnum], [buffer]
4158 hidnplayr 219
        test    eax, eax
220
        jz      .error
4167 hidnplayr 221
        DEBUGF  1, "Request has been sent to server.\n"
4158 hidnplayr 222
 
4167 hidnplayr 223
        HTTP_init_buffer [buffer], [socketnum]
224
 
4216 hidnplayr 225
        popa
226
        mov     eax, [buffer]   ; return buffer ptr
227
        ret
4167 hidnplayr 228
 
229
  .error:
230
        DEBUGF  1, "Error!\n"
4216 hidnplayr 231
        popa
4167 hidnplayr 232
        xor     eax, eax        ; return 0 = error
233
        ret
234
 
235
endp
236
 
237
 
238
 
239
;;================================================================================================;;
4221 hidnplayr 240
proc HTTP_head URL, add_header ;//////////////////////////////////////////////////////////////////;;
4167 hidnplayr 241
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 242
;? Initiates a HTTP connection, using 'HEAD' method.                                              ;;
4167 hidnplayr 243
;;------------------------------------------------------------------------------------------------;;
4221 hidnplayr 244
;> URL          = pointer to ASCIIZ URL                                                           ;;
245
;> add_header   = pointer to additional header parameters (ASCIIZ), or null for none.             ;;
4167 hidnplayr 246
;;------------------------------------------------------------------------------------------------;;
247
;< eax = 0 (error) / buffer ptr                                                                   ;;
248
;;================================================================================================;;
249
locals
250
        hostname        dd ?
251
        pageaddr        dd ?
252
        sockaddr        dd ?
253
        socketnum       dd ?
254
        buffer          dd ?
255
        port            dd ?
256
endl
257
 
4216 hidnplayr 258
        pusha
4167 hidnplayr 259
; split the URL into hostname and pageaddr
260
        stdcall parse_url, [URL]
4158 hidnplayr 261
        test    eax, eax
4167 hidnplayr 262
        jz      .error
263
        mov     [hostname], eax
264
        mov     [pageaddr], ebx
4221 hidnplayr 265
        mov     [port], ecx
4158 hidnplayr 266
 
4167 hidnplayr 267
; Connect to the other side.
268
        stdcall open_connection, [hostname], [port]
269
        test    eax, eax
270
        jz      .error
271
        mov     [socketnum], eax
272
 
4158 hidnplayr 273
; Create the HTTP request.
274
        invoke  mem.alloc, BUFFERSIZE
275
        test    eax, eax
276
        jz      .error
277
        mov     [buffer], eax
4167 hidnplayr 278
        mov     edi, eax
4158 hidnplayr 279
        DEBUGF  1, "Buffer has been allocated.\n"
280
 
4167 hidnplayr 281
        mov     esi, str_head
4158 hidnplayr 282
        copy_till_zero
283
 
4233 hidnplayr 284
; If we are using a proxy, send complete URL, otherwise send only page address.
285
        cmp     [proxyAddr], 0
286
        je      .no_proxy
287
        mov     esi, str_http           ; prepend 'http://'
288
        copy_till_zero
289
        mov     esi, [hostname]
290
        copy_till_zero
291
  .no_proxy:
4167 hidnplayr 292
        mov     esi, [pageaddr]
293
        copy_till_zero
294
 
4158 hidnplayr 295
        mov     esi, str_http11
296
        mov     ecx, str_http11.length
297
        rep     movsb
298
 
299
        mov     esi, [hostname]
300
        copy_till_zero
301
 
4221 hidnplayr 302
        mov     esi, [add_header]
303
        test    esi, esi
304
        jz      @f
305
        copy_till_zero
306
  @@:
307
 
4233 hidnplayr 308
        cmp     byte[proxyUser], 0
309
        je      @f
310
        call    append_proxy_auth_header
311
  @@:
312
 
4158 hidnplayr 313
        mov     esi, str_close
314
        mov     ecx, str_close.length
315
        rep     movsb
316
 
317
        mov     byte[edi], 0
318
        DEBUGF  1, "Request:\n%s", [buffer]
319
 
4222 hidnplayr 320
 
321
; Free unused memory
322
        push    edi
323
        invoke  mem.free, [pageaddr]
324
        invoke  mem.free, [hostname]
325
        pop     esi
326
 
4167 hidnplayr 327
; Send the request
4158 hidnplayr 328
        sub     esi, [buffer]   ; length
329
        xor     edi, edi        ; flags
330
        mcall   send, [socketnum], [buffer]
331
        test    eax, eax
332
        jz      .error
333
        DEBUGF  1, "Request has been sent to server.\n"
334
 
4167 hidnplayr 335
        HTTP_init_buffer [buffer], [socketnum]
4158 hidnplayr 336
 
4216 hidnplayr 337
        popa
338
        mov     eax, [buffer]
4167 hidnplayr 339
        ret                     ; return buffer ptr
4158 hidnplayr 340
 
4167 hidnplayr 341
  .error:
342
        DEBUGF  1, "Error!\n"
4216 hidnplayr 343
        popa
4167 hidnplayr 344
        xor     eax, eax        ; return 0 = error
345
        ret
346
 
347
endp
348
 
349
 
350
;;================================================================================================;;
4221 hidnplayr 351
proc HTTP_post URL, add_header, content_type, content_length ;////////////////////////////////////;;
4167 hidnplayr 352
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 353
;? Initiates a HTTP connection, using 'GET' method.                                               ;;
4167 hidnplayr 354
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 355
;> URL                  = pointer to ASCIIZ URL                                                   ;;
4221 hidnplayr 356
;> add_header           = pointer to additional header parameters (ASCIIZ), or null for none.     ;;
4202 hidnplayr 357
;> content_type         = pointer to ASCIIZ string containing content type                        ;;
358
;> content_length       = length of content (in bytes)                                            ;;
4167 hidnplayr 359
;;------------------------------------------------------------------------------------------------;;
360
;< eax = 0 (error) / buffer ptr                                                                   ;;
361
;;================================================================================================;;
362
locals
363
        hostname        dd ?
364
        pageaddr        dd ?
365
        sockaddr        dd ?
366
        socketnum       dd ?
367
        buffer          dd ?
368
        port            dd ?
369
endl
370
 
4216 hidnplayr 371
        pusha
4167 hidnplayr 372
; split the URL into hostname and pageaddr
373
        stdcall parse_url, [URL]
374
        test    eax, eax
375
        jz      .error
376
        mov     [hostname], eax
377
        mov     [pageaddr], ebx
4221 hidnplayr 378
        mov     [port], ecx
4167 hidnplayr 379
 
380
; Connect to the other side.
381
        stdcall open_connection, [hostname], [port]
382
        test    eax, eax
383
        jz      .error
384
        mov     [socketnum], eax
385
 
386
; Create the HTTP request.
387
        invoke  mem.alloc, BUFFERSIZE
388
        test    eax, eax
389
        jz      .error
390
        mov     [buffer], eax
391
        mov     edi, eax
392
        DEBUGF  1, "Buffer has been allocated.\n"
393
 
394
        mov     esi, str_post
395
        copy_till_zero
396
 
4233 hidnplayr 397
; If we are using a proxy, send complete URL, otherwise send only page address.
398
        cmp     [proxyAddr], 0
399
        je      .no_proxy
400
        mov     esi, str_http           ; prepend 'http://'
401
        copy_till_zero
402
        mov     esi, [hostname]
403
        copy_till_zero
404
  .no_proxy:
4167 hidnplayr 405
        mov     esi, [pageaddr]
406
        copy_till_zero
407
 
408
        mov     esi, str_http11
409
        mov     ecx, str_http11.length
410
        rep     movsb
411
 
412
        mov     esi, [hostname]
413
        copy_till_zero
414
 
415
        mov     esi, str_post_cl
416
        mov     ecx, str_post_cl.length
417
        rep     movsb
418
 
419
        mov     eax, [content_length]
4233 hidnplayr 420
        call    eax_ascii_dec
4167 hidnplayr 421
 
422
        mov     esi, str_post_ct
423
        mov     ecx, str_post_ct.length
424
        rep     movsb
425
 
426
        mov     esi, [content_type]
4221 hidnplayr 427
        copy_till_zero
4167 hidnplayr 428
 
4221 hidnplayr 429
        mov     esi, [add_header]
430
        test    esi, esi
431
        jz      @f
432
        copy_till_zero
433
  @@:
434
 
4233 hidnplayr 435
        cmp     byte[proxyUser], 0
436
        je      @f
437
        call    append_proxy_auth_header
438
  @@:
439
 
4167 hidnplayr 440
        mov     esi, str_close
441
        mov     ecx, str_close.length
442
        rep     movsb
443
 
444
        mov     byte[edi], 0
445
        DEBUGF  1, "Request:\n%s", [buffer]
446
 
4222 hidnplayr 447
; Free unused memory
448
        push    edi
449
        invoke  mem.free, [pageaddr]
450
        invoke  mem.free, [hostname]
451
        pop     esi
452
 
4167 hidnplayr 453
; Send the request
454
        sub     esi, [buffer]   ; length
455
        xor     edi, edi        ; flags
456
        mcall   send, [socketnum], [buffer]
457
        test    eax, eax
458
        jz      .error
459
        DEBUGF  1, "Request has been sent to server.\n"
460
 
461
        HTTP_init_buffer [buffer], [socketnum]
4206 hidnplayr 462
 
4216 hidnplayr 463
        popa
464
        mov     eax, [buffer]
4158 hidnplayr 465
        ret                     ; return buffer ptr
466
 
467
  .error:
468
        DEBUGF  1, "Error!\n"
4216 hidnplayr 469
        popa
4158 hidnplayr 470
        xor     eax, eax        ; return 0 = error
471
        ret
472
 
473
endp
474
 
475
 
476
 
477
;;================================================================================================;;
478
proc HTTP_process identifier ;////////////////////////////////////////////////////////////////////;;
479
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 480
;? Receive data from the server, parse headers and put data in receive buffer.                    ;;
481
;? To complete a transfer, this procedure must be called over and over again untill it returns 0. ;;
4158 hidnplayr 482
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 483
;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
4158 hidnplayr 484
;;------------------------------------------------------------------------------------------------;;
485
;< eax = -1 (not finished) / 0 finished                                                           ;;
486
;;================================================================================================;;
487
        pusha
488
        mov     ebp, [identifier]
4162 hidnplayr 489
 
4209 hidnplayr 490
; If the connection is closed, return immediately
4205 hidnplayr 491
        test    [ebp + http_msg.flags], FLAG_CONNECTED
492
        jz      .connection_closed
493
 
4162 hidnplayr 494
; Receive some data
4158 hidnplayr 495
        mcall   recv, [ebp + http_msg.socket], [ebp + http_msg.write_ptr], \
496
                      [ebp + http_msg.buffer_length], MSG_DONTWAIT
497
        cmp     eax, 0xffffffff
498
        je      .check_socket
4220 hidnplayr 499
 
500
        test    eax, eax
501
        jz      .server_closed
4158 hidnplayr 502
        DEBUGF  1, "Received %u bytes\n", eax
503
 
4209 hidnplayr 504
; Update timestamp
4206 hidnplayr 505
        push    eax
506
        mcall   29, 9
507
        mov     [ebp + http_msg.timestamp], eax
508
        pop     eax
509
 
4162 hidnplayr 510
; Update pointers
4158 hidnplayr 511
        mov     edi, [ebp + http_msg.write_ptr]
512
        add     [ebp + http_msg.write_ptr], eax
513
        sub     [ebp + http_msg.buffer_length], eax
514
        jz      .got_all_data
4162 hidnplayr 515
 
516
; If data is chunked, combine chunks into contiguous data.
517
        test    [ebp + http_msg.flags], FLAG_CHUNKED
518
        jnz     .chunk_loop
519
 
4212 hidnplayr 520
; Did we detect the (final) header yet?
4158 hidnplayr 521
        test    [ebp + http_msg.flags], FLAG_GOT_HEADER
522
        jnz     .header_parsed
523
 
4212 hidnplayr 524
; We havent found the (final) header yet, search for it..
525
  .scan_again:
526
        ; eax = total number of bytes received so far
527
        mov     eax, [ebp + http_msg.write_ptr]
528
        sub     eax, http_msg.data
529
        sub     eax, ebp
530
        sub     eax, [ebp + http_msg.header_length]
531
        ; edi is ptr to begin of header
532
        lea     edi, [ebp + http_msg.data]
533
        add     edi, [ebp + http_msg.header_length]
534
        ; put it in esi for next proc too
535
        mov     esi, edi
536
        sub     eax, 3
537
        jle     .need_more_data
538
  .scan_loop:
4158 hidnplayr 539
        ; scan for end of header (empty line)
540
        cmp     dword[edi], 0x0a0d0a0d                  ; end of header
541
        je      .end_of_header
4212 hidnplayr 542
        cmp     word[edi+2], 0x0a0a                     ; notice the use of offset + 2, to calculate header length correctly :)
4158 hidnplayr 543
        je      .end_of_header
544
        inc     edi
545
        dec     eax
4212 hidnplayr 546
        jnz     .scan_loop
547
        jmp     .need_more_data
4158 hidnplayr 548
 
549
  .end_of_header:
550
        add     edi, 4 - http_msg.data
551
        sub     edi, ebp
4212 hidnplayr 552
        mov     [ebp + http_msg.header_length], edi     ; If this isnt the final header, we'll use this as an offset to find real header.
4158 hidnplayr 553
        DEBUGF  1, "Header length: %u\n", edi
554
 
555
; Ok, we have found header:
4212 hidnplayr 556
        cmp     dword[esi], 'HTTP'
4158 hidnplayr 557
        jne     .invalid_header
4212 hidnplayr 558
        cmp     dword[esi+4], '/1.0'
4158 hidnplayr 559
        je      .http_1.0
4212 hidnplayr 560
        cmp     dword[esi+4], '/1.1'
4158 hidnplayr 561
        jne     .invalid_header
562
        or      [ebp + http_msg.flags], FLAG_HTTP11
563
  .http_1.0:
4212 hidnplayr 564
        cmp     byte[esi+8], ' '
4158 hidnplayr 565
        jne     .invalid_header
566
 
4212 hidnplayr 567
        add     esi, 9
4158 hidnplayr 568
        xor     eax, eax
569
        xor     ebx, ebx
570
        mov     ecx, 3
571
  .statusloop:
572
        lodsb
573
        sub     al, '0'
574
        jb      .invalid_header
575
        cmp     al, 9
576
        ja      .invalid_header
577
        lea     ebx, [ebx + 4*ebx]
578
        shl     ebx, 1
579
        add     ebx, eax
580
        dec     ecx
581
        jnz     .statusloop
4212 hidnplayr 582
 
583
; Ignore "100 - Continue" headers
584
        cmp     ebx, 100
585
        je      .scan_again
586
 
587
        DEBUGF  1, "Status: %u\n", ebx
4158 hidnplayr 588
        mov     [ebp + http_msg.status], ebx
4212 hidnplayr 589
        or      [ebp + http_msg.flags], FLAG_GOT_HEADER
4158 hidnplayr 590
 
591
; Now, convert all header names to lowercase.
592
; This way, it will be much easier to find certain header fields, later on.
593
 
594
        lea     esi, [ebp + http_msg.data]
595
        mov     ecx, [ebp + http_msg.header_length]
596
  .need_newline:
597
        inc     esi
598
        dec     ecx
599
        jz      .convert_done
600
        cmp     byte[esi], 10
601
        jne     .need_newline
602
; Ok, we have a newline, a line beginning with space or tabs has no header fields.
603
 
604
        inc     esi
605
        dec     ecx
606
        jz      .convert_done
607
        cmp     byte[esi], ' '
608
        je      .need_newline
609
        cmp     byte[esi], 9    ; horizontal tab
610
        je      .need_newline
611
        jmp     .convert_loop
612
  .next_char:
613
        inc     esi
614
        dec     ecx
615
        jz      .convert_done
616
  .convert_loop:
617
        cmp     byte[esi], ':'
618
        je      .need_newline
619
        cmp     byte[esi], 'A'
620
        jb      .next_char
621
        cmp     byte[esi], 'Z'
622
        ja      .next_char
623
        or      byte[esi], 0x20 ; convert to lowercase
624
        jmp     .next_char
625
  .convert_done:
626
        mov     byte[esi-1], 0
627
        lea     esi, [ebp + http_msg.data]
628
        DEBUGF  1, "Header names converted to lowercase:\n%s\n", esi
629
 
630
; Check for content-length header field.
4222 hidnplayr 631
        stdcall HTTP_find_header_field, ebp, str_cl
4158 hidnplayr 632
        test    eax, eax
633
        jz      .no_content
634
        or      [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
635
 
636
        xor     edx, edx
637
  .cl_loop:
638
        movzx   ebx, byte[eax]
639
        inc     eax
640
        cmp     bl, 10
641
        je      .cl_ok
642
        cmp     bl, 13
643
        je      .cl_ok
644
        cmp     bl, ' '
645
        je      .cl_ok
646
        sub     bl, '0'
647
        jb      .invalid_header
648
        cmp     bl, 9
649
        ja      .invalid_header
650
        lea     edx, [edx + edx*4]      ; edx = edx*10
651
        shl     edx, 1                  ;
652
        add     edx, ebx
653
        jmp     .cl_loop
654
 
655
  .cl_ok:
656
        mov     [ebp + http_msg.content_length], edx
657
        DEBUGF  1, "Content-length: %u\n", edx
658
 
659
; Resize buffer according to content-length.
4168 hidnplayr 660
        add     edx, [ebp + http_msg.header_length]
661
        add     edx, http_msg.data
4158 hidnplayr 662
 
4168 hidnplayr 663
        mov     ecx, edx
4158 hidnplayr 664
        sub     ecx, [ebp + http_msg.write_ptr]
665
        mov     [ebp + http_msg.buffer_length], ecx
666
 
4168 hidnplayr 667
        invoke  mem.realloc, ebp, edx
4158 hidnplayr 668
        or      eax, eax
4212 hidnplayr 669
        jz      .no_ram
4203 hidnplayr 670
 
4220 hidnplayr 671
  .not_chunked:
4212 hidnplayr 672
        mov     eax, [ebp + http_msg.write_ptr]
4168 hidnplayr 673
        sub     eax, [ebp + http_msg.header_length]
4212 hidnplayr 674
        sub     eax, http_msg.data
675
        sub     eax, ebp
4158 hidnplayr 676
        jmp     .header_parsed  ; hooray!
677
 
678
  .no_content:
679
        DEBUGF  1, "Content-length not found.\n"
680
 
681
; We didnt find 'content-length', maybe server is using chunked transfer encoding?
682
; Try to find 'transfer-encoding' header.
4222 hidnplayr 683
        stdcall HTTP_find_header_field, ebp, str_te
4158 hidnplayr 684
        test    eax, eax
4220 hidnplayr 685
        jz      .not_chunked
4158 hidnplayr 686
 
687
        mov     ebx, dword[eax]
4162 hidnplayr 688
        or      ebx, 0x20202020
4158 hidnplayr 689
        cmp     ebx, 'chun'
4220 hidnplayr 690
        jne     .not_chunked
4158 hidnplayr 691
        mov     ebx, dword[eax+4]
4162 hidnplayr 692
        or      ebx, 0x00202020
693
        and     ebx, 0x00ffffff
4158 hidnplayr 694
        cmp     ebx, 'ked'
4220 hidnplayr 695
        jne     .not_chunked
4158 hidnplayr 696
 
697
        or      [ebp + http_msg.flags], FLAG_CHUNKED
698
        DEBUGF  1, "Transfer type is: chunked\n"
699
 
700
; Set chunk pointer where first chunk should begin.
4162 hidnplayr 701
        lea     eax, [ebp + http_msg.data]
702
        add     eax, [ebp + http_msg.header_length]
4158 hidnplayr 703
        mov     [ebp + http_msg.chunk_ptr], eax
704
 
4162 hidnplayr 705
  .chunk_loop:
4158 hidnplayr 706
        mov     ecx, [ebp + http_msg.write_ptr]
707
        sub     ecx, [ebp + http_msg.chunk_ptr]
4202 hidnplayr 708
        jb      .need_more_data_chunked         ; TODO: use this ecx !!!
4158 hidnplayr 709
 
4202 hidnplayr 710
; Chunkline starts here, convert the ASCII hex number into ebx
4158 hidnplayr 711
        mov     esi, [ebp + http_msg.chunk_ptr]
712
        xor     ebx, ebx
713
  .chunk_hexloop:
714
        lodsb
715
        sub     al, '0'
716
        jb      .chunk_
717
        cmp     al, 9
718
        jbe     .chunk_hex
4162 hidnplayr 719
        sub     al, 'A' - '0' - 10
4158 hidnplayr 720
        jb      .chunk_
4162 hidnplayr 721
        cmp     al, 15
4158 hidnplayr 722
        jbe     .chunk_hex
723
        sub     al, 'a' - 'A'
4162 hidnplayr 724
        cmp     al, 15
4158 hidnplayr 725
        ja      .chunk_
726
  .chunk_hex:
727
        shl     ebx, 4
728
        add     bl, al
729
        jmp     .chunk_hexloop
730
  .chunk_:
731
        DEBUGF  1, "got chunk of %u bytes\n", ebx
4202 hidnplayr 732
;;        cmp     esi, [ebp + http_msg.chunk_ptr]
733
;;        je
4158 hidnplayr 734
; If chunk size is 0, all chunks have been received.
735
        test    ebx, ebx
4162 hidnplayr 736
        jz      .got_all_data_chunked           ; last chunk, hooray! FIXME: what if it wasnt a valid hex number???
4158 hidnplayr 737
 
738
; Chunkline ends with a CR, LF or simply LF
4202 hidnplayr 739
  .end_of_chunkline?:
4158 hidnplayr 740
        cmp     al, 10
741
        je      .end_of_chunkline
742
        lodsb
4202 hidnplayr 743
        cmp     edi, [ebp + http_msg.write_ptr]
744
        jb      .end_of_chunkline?
745
        jmp     .need_more_data
4158 hidnplayr 746
 
747
  .end_of_chunkline:
4202 hidnplayr 748
; Update chunk ptr, and remember old one
749
        mov     edi, [ebp + http_msg.chunk_ptr]
750
        add     [ebp + http_msg.chunk_ptr], ebx
4162 hidnplayr 751
; Realloc buffer, make it 'chunksize' bigger.
752
        mov     eax, [ebp + http_msg.buffer_length]
753
        add     eax, ebx
754
        invoke  mem.realloc, ebp, eax
755
        or      eax, eax
756
        jz      .no_ram
757
        add     [ebp + http_msg.buffer_length], ebx
758
 
759
; Update write ptr
760
        mov     eax, esi
761
        sub     eax, edi
762
        sub     [ebp + http_msg.write_ptr], eax
763
 
4158 hidnplayr 764
; Now move all received data to the left (remove chunk header).
4162 hidnplayr 765
; Update content_length accordingly.
4158 hidnplayr 766
        mov     ecx, [ebp + http_msg.write_ptr]
767
        sub     ecx, esi
4168 hidnplayr 768
        add     [ebp + http_msg.content_received], ecx
4158 hidnplayr 769
        rep     movsb
4162 hidnplayr 770
        jmp     .chunk_loop
4158 hidnplayr 771
 
772
; Check if we got all the data.
4162 hidnplayr 773
  .header_parsed:
4168 hidnplayr 774
        add     [ebp + http_msg.content_received], eax
4220 hidnplayr 775
        test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
776
        jz      .need_more_data_and_space
4217 hidnplayr 777
        mov     eax, [ebp + http_msg.content_received]
778
        cmp     eax, [ebp + http_msg.content_length]
4168 hidnplayr 779
        jae     .got_all_data
4220 hidnplayr 780
        jmp     .need_more_data
4212 hidnplayr 781
 
4220 hidnplayr 782
  .need_more_data_and_space:
783
        mov     eax, [ebp + http_msg.write_ptr]
784
        add     eax, BUFFERSIZE
785
        sub     eax, ebp
786
        invoke  mem.realloc, ebp, eax
787
        or      eax, eax
788
        jz      .no_ram
789
        mov     [ebp + http_msg.buffer_length], BUFFERSIZE
790
 
4162 hidnplayr 791
  .need_more_data:
792
        popa
793
        xor     eax, eax
794
        dec     eax
795
        ret
4158 hidnplayr 796
 
4162 hidnplayr 797
  .need_more_data_chunked:
4168 hidnplayr 798
        add     [ebp + http_msg.content_received], eax
4158 hidnplayr 799
        popa
800
        xor     eax, eax
801
        dec     eax
802
        ret
803
 
4162 hidnplayr 804
  .got_all_data_chunked:
805
        mov     eax, [ebp + http_msg.chunk_ptr]
806
        sub     eax, [ebp + http_msg.header_length]
807
        sub     eax, http_msg.data
808
        sub     eax, ebp
809
        mov     [ebp + http_msg.content_length], eax
4168 hidnplayr 810
        mov     [ebp + http_msg.content_received], eax
4158 hidnplayr 811
  .got_all_data:
4217 hidnplayr 812
        DEBUGF  1, "We got all the data! (%u bytes)\n", [ebp + http_msg.content_received]
4205 hidnplayr 813
        or      [ebp + http_msg.flags], FLAG_GOT_ALL_DATA
814
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
4158 hidnplayr 815
        mcall   close, [ebp + http_msg.socket]
816
        popa
817
        xor     eax, eax
818
        ret
819
 
820
  .check_socket:
821
        cmp     ebx, EWOULDBLOCK
4206 hidnplayr 822
        jne     .socket_error
4158 hidnplayr 823
 
4206 hidnplayr 824
        mcall   29, 9
825
        sub     eax, TIMEOUT
826
        cmp     eax, [ebp + http_msg.timestamp]
4207 hidnplayr 827
        jb      .need_more_data
4206 hidnplayr 828
        DEBUGF  1, "ERROR: timeout\n"
829
        or      [ebp + http_msg.flags], FLAG_TIMEOUT_ERROR
830
        jmp     .disconnect
4158 hidnplayr 831
 
4220 hidnplayr 832
  .server_closed:
833
        DEBUGF  1, "server closed connection, transfer complete?\n"
834
        test    [ebp + http_msg.flags], FLAG_GOT_HEADER
835
        jz      .server_error
836
        test    [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
837
        jz      .got_all_data
838
 
839
  .server_error:
840
        pop     eax
841
        DEBUGF  1, "ERROR: server closed connection unexpectedly\n"
842
        or      [ebp + http_msg.flags], FLAG_TRANSFER_FAILED
843
        jmp     .disconnect
844
 
4158 hidnplayr 845
  .invalid_header:
4203 hidnplayr 846
        pop     eax
4158 hidnplayr 847
        DEBUGF  1, "ERROR: invalid header\n"
848
        or      [ebp + http_msg.flags], FLAG_INVALID_HEADER
4206 hidnplayr 849
        jmp     .disconnect
4158 hidnplayr 850
 
851
  .no_ram:
852
        DEBUGF  1, "ERROR: out of RAM\n"
853
        or      [ebp + http_msg.flags], FLAG_NO_RAM
4206 hidnplayr 854
        jmp     .disconnect
855
 
856
  .socket_error:
857
        DEBUGF  1, "ERROR: socket error %u\n", ebx
858
        or      [ebp + http_msg.flags], FLAG_SOCKET_ERROR
859
  .disconnect:
4205 hidnplayr 860
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
861
        mcall   close, [ebp + http_msg.socket]
4206 hidnplayr 862
  .connection_closed:
4158 hidnplayr 863
        popa
864
        xor     eax, eax
865
        ret
866
 
867
endp
868
 
869
 
870
 
4205 hidnplayr 871
 
4158 hidnplayr 872
;;================================================================================================;;
4205 hidnplayr 873
proc HTTP_free identifier ;///////////////////////////////////////////////////////////////////////;;
874
;;------------------------------------------------------------------------------------------------;;
875
;? Free the http_msg structure                                                                    ;;
876
;;------------------------------------------------------------------------------------------------;;
877
;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
878
;;------------------------------------------------------------------------------------------------;;
879
;< none                                                                                           ;;
880
;;================================================================================================;;
881
 
882
        pusha
883
        mov     ebp, [identifier]
884
 
885
        test    [ebp + http_msg.flags], FLAG_CONNECTED
886
        jz      .not_connected
887
 
888
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
889
        mcall   close, [ebp + http_msg.socket]
890
 
891
  .not_connected:
892
        invoke  mem.free, ebp
893
 
894
        popa
895
        ret
896
 
897
endp
898
 
899
 
900
 
901
;;================================================================================================;;
902
proc HTTP_stop identifier ;///////////////////////////////////////////////////////////////////////;;
903
;;------------------------------------------------------------------------------------------------;;
904
;? Stops the open connection                                                                      ;;
905
;;------------------------------------------------------------------------------------------------;;
906
;> identifier   = pointer to buffer containing http_msg struct.                                   ;;
907
;;------------------------------------------------------------------------------------------------;;
908
;< none                                                                                           ;;
909
;;================================================================================================;;
910
 
911
        pusha
912
        mov     ebp, [identifier]
913
 
914
        and     [ebp + http_msg.flags], not FLAG_CONNECTED
915
        mcall   close, [ebp + http_msg.socket]
916
 
917
        popa
918
        ret
919
 
920
endp
921
 
922
 
923
 
924
;;================================================================================================;;
4222 hidnplayr 925
proc HTTP_find_header_field identifier, headername ;//////////////////////////////////////////////;;
4158 hidnplayr 926
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 927
;? Find a header field in the received HTTP header                                                ;;
4158 hidnplayr 928
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 929
;> identifier   = ptr to http_msg struct                                                          ;;
930
;> headername   = ptr to ASCIIZ string containg field you want to find (must be in lowercase)     ;;
4158 hidnplayr 931
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 932
;< eax = 0 (error) / ptr to content of the HTTP header field                                      ;;
4158 hidnplayr 933
;;================================================================================================;;
934
        push    ebx ecx edx esi edi
935
 
936
        DEBUGF  1, "Find header field: %s\n", [headername]
937
 
938
        mov     ebx, [identifier]
4202 hidnplayr 939
        test    [ebx + http_msg.flags], FLAG_GOT_HEADER
940
        jz      .fail
941
 
4158 hidnplayr 942
        lea     edx, [ebx + http_msg.data]
943
        mov     ecx, edx
944
        add     ecx, [ebx + http_msg.header_length]
945
 
946
  .restart:
947
        mov     esi, [headername]
948
        mov     edi, edx
949
  .loop:
950
        cmp     edi, ecx
951
        jae     .fail
952
        lodsb
953
        scasb
954
        je      .loop
955
        test    al, al
956
        jz      .done?
957
  .next:
958
        inc     edx
959
        jmp     .restart
960
 
961
  .not_done:
962
        inc     edi
963
  .done?:
964
        cmp     byte[edi-1], ':'
965
        je      .almost_done
966
        cmp     byte[edi-1], ' '
967
        je      .not_done
968
        cmp     byte[edi-1], 9  ; tab
969
        je      .not_done
970
 
971
        jmp     .next
972
 
973
  .almost_done:                 ; FIXME: buffer overflow?
974
        dec     edi
975
        DEBUGF  1, "Found header field\n"
976
  .spaceloop:
977
        inc     edi
978
        cmp     byte[edi], ' '
979
        je      .spaceloop
980
        cmp     byte[edi], 9    ; tab
981
        je      .spaceloop
982
 
983
        mov     eax, edi
984
        pop     edi esi edx ecx ebx
985
        ret
986
 
987
  .fail:
988
        pop     edi esi edx ecx ebx
989
        xor     eax, eax
990
        ret
991
 
992
endp
993
 
994
 
995
 
4209 hidnplayr 996
;;================================================================================================;;
997
proc URI_escape URI ;/////////////////////////////////////////////////////////////////////////////;;
998
;;------------------------------------------------------------------------------------------------;;
999
;?                                                                                                ;;
1000
;;------------------------------------------------------------------------------------------------;;
1001
;> URI = ptr to ASCIIZ URI                                                                        ;;
1002
;;------------------------------------------------------------------------------------------------;;
1003
;< eax = 0 (error) / ptr to ASCIIZ URI                                                            ;;
1004
;;================================================================================================;;
4202 hidnplayr 1005
 
4209 hidnplayr 1006
        pusha
4205 hidnplayr 1007
 
4209 hidnplayr 1008
        invoke  mem.alloc, URLMAXLEN
1009
        test    eax, eax
1010
        jz      .error
1011
        mov     [esp + 7 * 4], eax              ; return ptr in eax
1012
        mov     esi, [URI]
1013
        mov     edi, eax
1014
        xor     ebx, ebx
1015
        xor     ecx, ecx
1016
  .loop:
1017
        lodsb
1018
        test    al, al
1019
        jz      .done
1020
 
1021
        mov     cl, al
1022
        and     cl, 0x1f
1023
        mov     bl, al
1024
        shr     bl, 5
1025
        bt      dword[bits_must_escape + ebx], ecx
1026
        jc      .escape
1027
 
1028
        stosb
1029
        jmp     .loop
1030
 
1031
  .escape:
1032
        mov     al, '%'
1033
        stosb
1034
        mov     bl, byte[esi-1]
1035
        shr     bl, 4
1036
        mov     al, byte[str_hex + ebx]
1037
        stosb
1038
        mov     bl, byte[esi-1]
1039
        and     bl, 0x0f
1040
        mov     al, byte[str_hex + ebx]
1041
        stosb
1042
        jmp     .loop
1043
 
1044
 
1045
  .done:
1046
        stosb
1047
 
1048
        popa
1049
        ret
1050
 
1051
  .error:
1052
        popa
1053
        xor     eax, eax
1054
        ret
1055
 
1056
endp
1057
 
1058
 
1059
 
4167 hidnplayr 1060
;;================================================================================================;;
4209 hidnplayr 1061
proc URI_unescape URI ;///////////////////////////////////////////////////////////////////////////;;
1062
;;------------------------------------------------------------------------------------------------;;
1063
;?                                                                                                ;;
1064
;;------------------------------------------------------------------------------------------------;;
1065
;> URI = ptr to ASCIIZ URI                                                                        ;;
1066
;;------------------------------------------------------------------------------------------------;;
1067
;< eax = 0 (error) / ptr to ASCIIZ URI                                                            ;;
1068
;;================================================================================================;;
1069
 
1070
        pusha
1071
 
1072
        invoke  mem.alloc, URLMAXLEN
1073
        test    eax, eax
1074
        jz      .error
1075
        mov     [esp + 7 * 4], eax              ; return ptr in eax
1076
        mov     esi, [URI]
1077
        mov     edi, eax
1078
  .loop:
1079
        lodsb
1080
        test    al, al
1081
        jz      .done
1082
 
1083
        cmp     al, '%'
1084
        je      .unescape
1085
 
1086
        stosb
1087
        jmp     .loop
1088
 
1089
  .unescape:
1090
        xor     ebx, ebx
1091
        xor     ecx, ecx
1092
  .unescape_nibble:
1093
        lodsb
1094
        sub     al, '0'
1095
        jb      .fail
1096
        cmp     al, 9
1097
        jbe     .nibble_ok
1098
        sub     al, 'A' - '0' - 10
1099
        jb      .fail
1100
        cmp     al, 15
1101
        jbe     .nibble_ok
1102
        sub     al, 'a' - 'A'
1103
        cmp     al, 15
1104
        ja      .fail
1105
  .nibble_ok:
1106
        shl     bl, 8
1107
        or      bl, al
1108
        dec     ecx
1109
        jc      .unescape_nibble
1110
        mov     al, bl
1111
        stosb
1112
        jmp     .loop
1113
 
1114
  .fail:
1115
        DEBUGF  1, "ERROR: invalid URI!\n"
1116
        jmp     .loop
1117
 
1118
  .done:
1119
        stosb
1120
 
1121
        popa
1122
        ret
1123
 
1124
  .error:
1125
        popa
1126
        xor     eax, eax
1127
        ret
1128
 
1129
endp
1130
 
1131
 
1132
 
1133
 
1134
 
1135
;;================================================================================================;;
4202 hidnplayr 1136
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1137
;;================================================================================================;;
1138
;! Internal procedures section                                                                    ;;
4220 hidnplayr 1139
;;                                                                                                ;;
1140
;; NOTICE: These procedures do not follow stdcall conventions and thus may destroy any register.  ;;
4202 hidnplayr 1141
;;================================================================================================;;
1142
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1143
;;================================================================================================;;
1144
 
1145
 
1146
 
1147
 
1148
;;================================================================================================;;
4167 hidnplayr 1149
proc open_connection hostname, port ;/////////////////////////////////////////////////////////////;;
1150
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1151
;? Connects to a HTTP server                                                                      ;;
4167 hidnplayr 1152
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1153
;> hostname     = ptr to ASCIIZ hostname                                                          ;;
1154
;> port         = port (x86 byte order)                                                           ;;
4167 hidnplayr 1155
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1156
;< eax = 0 (error) / socketnum                                                                    ;;
4167 hidnplayr 1157
;;================================================================================================;;
4158 hidnplayr 1158
 
4167 hidnplayr 1159
locals
1160
        sockaddr        dd ?
1161
        socketnum       dd ?
1162
endl
1163
 
4233 hidnplayr 1164
        cmp     [proxyAddr], 0
1165
        je      .no_proxy
1166
 
1167
        mov     [hostname], proxyAddr
1168
 
1169
        push    [proxyPort]
1170
        pop     [port]
1171
  .no_proxy:
1172
 
4167 hidnplayr 1173
; Resolve the hostname
1174
        DEBUGF  1, "Resolving hostname\n"
1175
        push    esp     ; reserve stack place
1176
        push    esp     ; fourth parameter
1177
        push    0       ; third parameter
1178
        push    0       ; second parameter
1179
        push    [hostname]
1180
        call    [getaddrinfo]
1181
        pop     esi
1182
        test    eax, eax
1183
        jnz     .error1
1184
 
1185
; getaddrinfo returns addrinfo struct, make the pointer to sockaddr struct
1186
        mov     esi, [esi + addrinfo.ai_addr]
1187
        mov     [sockaddr], esi
1188
        mov     eax, [esi + sockaddr_in.sin_addr]
1189
        test    eax, eax
1190
        jz      .error2
1191
 
1192
        DEBUGF  1, "Server ip=%u.%u.%u.%u\n", \
1193
        [esi + sockaddr_in.sin_addr]:1, [esi + sockaddr_in.sin_addr + 1]:1, \
1194
        [esi + sockaddr_in.sin_addr + 2]:1, [esi + sockaddr_in.sin_addr + 3]:1
1195
 
1196
        mov     [esi + sockaddr_in.sin_family], AF_INET4
1197
        mov     eax, [port]
1198
        xchg    al, ah
1199
        mov     [esi + sockaddr_in.sin_port], ax
1200
 
1201
; Connect to the server.
1202
        mcall   socket, AF_INET4, SOCK_STREAM, 0
1203
        test    eax, eax
1204
        jz      .error2
1205
        mov     [socketnum], eax
1206
        DEBUGF  1, "Socket: 0x%x\n", eax
1207
 
1208
        mcall   connect, [socketnum], [sockaddr], 18
1209
        test    eax, eax
1210
        jnz     .error2
1211
        DEBUGF  1, "Socket is now connected.\n"
1212
 
1213
; free allocated memory
1214
        push    [sockaddr]
1215
        call    [freeaddrinfo]
1216
 
1217
        mov     eax, [socketnum]
1218
        ret
1219
 
1220
  .error2:
1221
 
1222
; free allocated memory
1223
        push    [sockaddr]
1224
        call    [freeaddrinfo]
1225
 
1226
  .error1:
1227
        xor     eax, eax
1228
        ret
1229
 
1230
endp
1231
 
1232
 
4158 hidnplayr 1233
;;================================================================================================;;
1234
proc parse_url URL ;//////////////////////////////////////////////////////////////////////////////;;
1235
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1236
;? Split a given URL into hostname and pageaddr                                                   ;;
4158 hidnplayr 1237
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1238
;> URL = ptr to ASCIIZ URL                                                                        ;;
4158 hidnplayr 1239
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1240
;< eax = 0 (error) / ptr to ASCIIZ hostname                                                       ;;
1241
;< ebx = ptr to ASCIIZ pageaddr                                                                   ;;
4233 hidnplayr 1242
;< ecx = port number                                                                              ;;
4158 hidnplayr 1243
;;================================================================================================;;
1244
 
1245
locals
1246
        urlsize         dd ?
1247
        hostname        dd ?
1248
        pageaddr        dd ?
4233 hidnplayr 1249
        port            dd ?
4158 hidnplayr 1250
endl
1251
 
4161 hidnplayr 1252
        DEBUGF  1, "parsing URL: %s\n", [URL]
4158 hidnplayr 1253
 
1254
; remove any leading protocol text
1255
        mov     esi, [URL]
1256
        mov     ecx, URLMAXLEN
1257
        mov     ax, '//'
1258
  .loop1:
1259
        cmp     byte[esi], 0            ; end of URL?
1260
        je      .url_ok                 ; yep, so not found
1261
        cmp     [esi], ax
1262
        je      .skip_proto
1263
        inc     esi
1264
        dec     ecx
1265
        jnz     .loop1
4233 hidnplayr 1266
        jmp     .invalid
4158 hidnplayr 1267
 
1268
  .skip_proto:
1269
        inc     esi                     ; skip the two '/'
1270
        inc     esi
1271
        mov     [URL], esi              ; update pointer so it skips protocol
1272
        jmp     .loop1                  ; we still need to find the length of the URL
1273
 
1274
  .url_ok:
1275
        sub     esi, [URL]              ; calculate total length of URL
1276
        mov     [urlsize], esi
1277
 
1278
 
1279
; now look for page delimiter - it's a '/' character
1280
        mov     ecx, esi                ; URL length
1281
        mov     edi, [URL]
1282
        mov     al, '/'
1283
        repne   scasb
4161 hidnplayr 1284
        jne     @f
4158 hidnplayr 1285
        dec     edi                     ; return one char, '/' must be part of the pageaddr
1286
        inc     ecx                     ;
4161 hidnplayr 1287
  @@:
4158 hidnplayr 1288
        push    ecx edi                 ; remember the pointer and length of pageaddr
1289
 
4222 hidnplayr 1290
 
4233 hidnplayr 1291
; Create new buffer and put hostname in it.
4158 hidnplayr 1292
        mov     ecx, edi
1293
        sub     ecx, [URL]
1294
        inc     ecx                     ; we will add a 0 byte at the end
1295
        invoke  mem.alloc, ecx
1296
        or      eax, eax
1297
        jz      .no_mem
1298
 
1299
        mov     [hostname], eax         ; copy hostname to buffer
1300
        mov     edi, eax
1301
        mov     esi, [URL]
1302
        dec     ecx
1303
        rep     movsb
1304
        xor     al, al
1305
        stosb
1306
 
4233 hidnplayr 1307
; Check if user provided a port, and convert it if so.
1308
        mov     esi, [hostname]
1309
        mov     [port], 80              ; default port if user didnt provide one
1310
  .portloop:
1311
        lodsb
1312
        test    al, al
1313
        jz      .no_port
1314
        cmp     al, ':'
1315
        jne     .portloop
1316
 
1317
        push    esi
1318
        call    ascii_dec_ebx
1319
        pop     edi
1320
        cmp     byte[esi-1], 0
1321
        jne     .invalid
1322
        cmp     [proxyAddr], 0          ; remove port number from hostname
1323
        jne     @f                      ; unless when we are using proxy
1324
        mov     byte[edi-1], 0
1325
  @@:
1326
        test    ebx, ebx
1327
        je      .invalid
1328
        cmp     ebx, 0xffff
1329
        ja      .invalid
1330
        mov     [port], ebx
1331
  .no_port:
1332
 
1333
 
1334
; Did user provide a pageaddr?
4161 hidnplayr 1335
        mov     [pageaddr], str_slash   ; assume there is no pageaddr
4158 hidnplayr 1336
        pop     esi ecx
1337
        test    ecx, ecx
1338
        jz      .no_page
4233 hidnplayr 1339
 
1340
; Create new buffer and put pageaddr into it.
4158 hidnplayr 1341
        inc     ecx                     ; we will add a 0 byte at the end
1342
        invoke  mem.alloc, ecx
1343
        or      eax, eax
1344
        jz      .no_mem
1345
 
1346
        mov     [pageaddr], eax         ; copy pageaddr to buffer
1347
        mov     edi, eax
1348
        dec     ecx
1349
        rep     movsb
1350
        xor     al, al
1351
        stosb
4233 hidnplayr 1352
 
4158 hidnplayr 1353
  .no_page:
1354
        mov     eax, [hostname]
1355
        mov     ebx, [pageaddr]
4233 hidnplayr 1356
        mov     ecx, [port]
4158 hidnplayr 1357
 
1358
        DEBUGF  1, "hostname: %s\n", eax
1359
        DEBUGF  1, "pageaddr: %s\n", ebx
4221 hidnplayr 1360
        DEBUGF  1, "port: %u\n", ecx
4158 hidnplayr 1361
 
1362
        ret
1363
 
1364
  .no_mem:
4233 hidnplayr 1365
        DEBUGF  1, "Out of memory!\n"
4158 hidnplayr 1366
        xor     eax, eax
1367
        ret
1368
 
4233 hidnplayr 1369
  .invalid:
1370
        DEBUGF  1, "Invalid URL!\n"
1371
        xor     eax, eax
1372
        ret
1373
 
4158 hidnplayr 1374
endp
1375
 
1376
 
4233 hidnplayr 1377
 
1378
 
1379
 
4202 hidnplayr 1380
;;================================================================================================;;
4233 hidnplayr 1381
proc append_proxy_auth_header ;///////////////////////////////////////////////////////////////////;;
4202 hidnplayr 1382
;;------------------------------------------------------------------------------------------------;;
4233 hidnplayr 1383
;? Appends the proxy authentication header                                                        ;;
1384
;;------------------------------------------------------------------------------------------------;;
1385
;> /                                                                                              ;;
1386
;;------------------------------------------------------------------------------------------------;;
1387
;< /                                                                                              ;;
1388
;;================================================================================================;;
1389
        mov     esi, str_proxy_auth
1390
        mov     ecx, str_proxy_auth.length
1391
        rep     movsb
1392
; base64-encode string :
1393
        mov     esi, proxyUser
1394
 
1395
apah000:
1396
        lodsb
1397
        test    al, al
1398
        jz      apah001
1399
        call    encode_base64_byte
1400
        jmp     apah000
1401
 
1402
apah001:
1403
        mov     al, ':'
1404
        call    encode_base64_byte
1405
        mov     esi, proxyPassword
1406
 
1407
apah002:
1408
        lodsb
1409
        test    al, al
1410
        jz      apah003
1411
        call    encode_base64_byte
1412
        jmp     apah002
1413
 
1414
apah003:
1415
        call    encode_base64_final
1416
        ret
1417
 
1418
encode_base64_byte:
1419
        inc     ecx
1420
        shl     edx, 8
1421
        mov     dl, al
1422
        cmp     ecx, 3
1423
        je      ebb001
1424
        ret
1425
 
1426
ebb001:
1427
        shl     edx, 8
1428
        inc     ecx
1429
 
1430
ebb002:
1431
        rol     edx, 6
1432
        xor     eax, eax
1433
        xchg    al, dl
1434
        mov     al, [base64_table+eax]
1435
        stosb
1436
        loop    ebb002
1437
        ret
1438
 
1439
encode_base64_final:
1440
        mov     al, 0
1441
        test    ecx, ecx
1442
        jz      ebf000
1443
        call    encode_base64_byte
1444
        test    ecx, ecx
1445
        jz      ebf001
1446
        call    encode_base64_byte
1447
        mov     byte [edi-2], '='
1448
 
1449
ebf001:
1450
        mov     byte [edi-1], '='
1451
 
1452
ebf000:
1453
        ret
1454
 
1455
endp
1456
 
1457
 
1458
;;================================================================================================;;
1459
proc eax_ascii_dec ;//////////////////////////////////////////////////////////////////////////////;;
1460
;;------------------------------------------------------------------------------------------------;;
4202 hidnplayr 1461
;? Convert eax to ASCII decimal number                                                            ;;
1462
;;------------------------------------------------------------------------------------------------;;
1463
;> eax = number                                                                                   ;;
1464
;> edi = ptr where to write ASCII decimal number                                                  ;;
1465
;;------------------------------------------------------------------------------------------------;;
1466
;< /                                                                                              ;;
1467
;;================================================================================================;;
4158 hidnplayr 1468
 
4168 hidnplayr 1469
        push    -'0'
4167 hidnplayr 1470
        mov     ecx, 10
1471
  .loop:
1472
        xor     edx, edx
1473
        div     ecx
1474
        add     dl, '0'
4168 hidnplayr 1475
        push    edx
4167 hidnplayr 1476
        test    eax, eax
1477
        jnz     .loop
4158 hidnplayr 1478
 
4168 hidnplayr 1479
  .loop2:
1480
        pop     eax
1481
        add     al, '0'
1482
        jz      .done
1483
        stosb
1484
        jmp     .loop2
1485
  .done:
1486
 
4167 hidnplayr 1487
        ret
4158 hidnplayr 1488
 
4202 hidnplayr 1489
endp
4167 hidnplayr 1490
 
4202 hidnplayr 1491
 
4158 hidnplayr 1492
;;================================================================================================;;
4233 hidnplayr 1493
proc ascii_dec_ebx ;//////////////////////////////////////////////////////////////////////////////;;
1494
;;------------------------------------------------------------------------------------------------;;
1495
;? Convert ASCII decimal number to ebx                                                            ;;
1496
;;------------------------------------------------------------------------------------------------;;
1497
;> esi = ptr where to read ASCII decimal number                                                   ;;
1498
;;------------------------------------------------------------------------------------------------;;
1499
;> ebx = number                                                                                   ;;
1500
;;================================================================================================;;
1501
 
1502
        xor     eax, eax
1503
        xor     ebx, ebx
1504
  .loop:
1505
        lodsb
1506
        sub     al, '0'
1507
        jb      .done
1508
        cmp     al, 9
1509
        ja      .done
1510
        lea     ebx, [ebx + 4*ebx]
1511
        shl     ebx, 1
1512
        add     ebx, eax
1513
        jmp     .loop
1514
  .done:
1515
 
1516
        ret
1517
 
1518
endp
1519
 
1520
 
1521
;;================================================================================================;;
4158 hidnplayr 1522
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1523
;;================================================================================================;;
1524
;! Imported functions section                                                                     ;;
1525
;;================================================================================================;;
1526
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
1527
;;================================================================================================;;
1528
 
1529
 
1530
align 16
1531
@IMPORT:
1532
 
1533
library \
1534
        libini, 'libini.obj', \
1535
        network, 'network.obj'
1536
 
1537
import  libini, \
1538
        ini.get_str, 'ini_get_str', \
1539
        ini.get_int, 'ini_get_int'
1540
 
1541
import  network,\
1542
        getaddrinfo, 'getaddrinfo',\
1543
        freeaddrinfo,  'freeaddrinfo',\
1544
        inet_ntoa, 'inet_ntoa'
1545
 
1546
;;===========================================================================;;
1547
;;///////////////////////////////////////////////////////////////////////////;;
1548
;;===========================================================================;;
1549
;! Exported functions section                                                ;;
1550
;;===========================================================================;;
1551
;;///////////////////////////////////////////////////////////////////////////;;
1552
;;===========================================================================;;
1553
 
1554
 
1555
align 4
1556
@EXPORT:
1557
export  \
1558
        lib_init                , 'lib_init'            , \
1559
        0x00010001              , 'version'             , \
1560
        HTTP_get                , 'get'                 , \
4167 hidnplayr 1561
        HTTP_head               , 'head'                , \
1562
        HTTP_post               , 'post'                , \
4222 hidnplayr 1563
        HTTP_find_header_field  , 'find_header_field'   , \
4205 hidnplayr 1564
        HTTP_process            , 'process'             , \
1565
        HTTP_free               , 'free'                , \
4209 hidnplayr 1566
        HTTP_stop               , 'stop'                , \
1567
        URI_escape              , 'escape'              , \
1568
        URI_unescape            , 'unescape'
4158 hidnplayr 1569
 
1570
;        HTTP_put                , 'put'                 , \
1571
;        HTTP_delete             , 'delete'              , \
1572
;        HTTP_trace              , 'trace'               , \
1573
;        HTTP_connect            , 'connect'             , \
1574
 
1575
 
1576
 
1577
section '.data' data readable writable align 16
1578
 
1579
inifile         db '/sys/settings/network.ini', 0
1580
 
1581
sec_proxy:
1582
key_proxy       db 'proxy', 0
1583
key_proxyport   db 'port', 0
1584
key_user        db 'user', 0
1585
key_password    db 'password', 0
1586
 
1587
str_http11      db ' HTTP/1.1', 13, 10, 'Host: '
1588
  .length       = $ - str_http11
4167 hidnplayr 1589
str_post_cl     db 13, 10, 'Content-Length: '
1590
  .length       = $ - str_post_cl
1591
str_post_ct     db 13, 10, 'Content-Type: '
1592
  .length       = $ - str_post_ct
4158 hidnplayr 1593
str_close       db 13, 10, 'User-Agent: KolibriOS libHTTP/1.0', 13, 10, 'Connection: Close', 13, 10, 13, 10
1594
  .length       = $ - str_close
1595
str_proxy_auth  db 13, 10, 'Proxy-Authorization: Basic '
1596
  .length       = $ - str_proxy_auth
1597
 
4233 hidnplayr 1598
str_http        db 'http://', 0
1599
 
4158 hidnplayr 1600
base64_table    db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
1601
                db '0123456789+/'
1602
 
1603
str_cl          db 'content-length', 0
4161 hidnplayr 1604
str_slash       db '/', 0
4158 hidnplayr 1605
str_te          db 'transfer-encoding', 0
4167 hidnplayr 1606
str_get         db 'GET ', 0
1607
str_head        db 'HEAD ', 0
1608
str_post        db 'POST ', 0
4158 hidnplayr 1609
 
4209 hidnplayr 1610
bits_must_escape:
1611
dd      0xffffffff                                                      ; 00-1F
1612
dd      1 shl 0 + 1 shl 2 + 1 shl 3 + 1 shl 5 + 1 shl 28 + 1 shl 30     ; "#%<>
1613
dd      1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 30                       ;[\]^
1614
dd      1 shl 0 + 1 shl 27 + 1 shl 28 + 1 shl 29 + 1 shl 31             ;`{|} DEL
1615
 
1616
dd      0xffffffff
1617
dd      0xffffffff
1618
dd      0xffffffff
1619
dd      0xffffffff
1620
 
1621
str_hex:
1622
db '0123456789ABCDEF'
1623
 
4158 hidnplayr 1624
include_debug_strings
1625
 
1626
; uninitialized data
1627
mem.alloc       dd ?
1628
mem.free        dd ?
1629
mem.realloc     dd ?
1630
dll.load        dd ?
1631
 
1632
proxyAddr       rb 256
1633
proxyUser       rb 256
1634
proxyPassword   rb 256
1635
proxyPort       dd ?