Subversion Repositories Kolibri OS

Rev

Rev 4162 | Rev 4168 | 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                            ;;
9
;;                                                                 ;;
10
;;         GNU GENERAL PUBLIC LICENSE                              ;;
11
;;          Version 2, June 1991                                   ;;
12
;;                                                                 ;;
13
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14
 
15
; references:
16
; "HTTP made really easy", http://www.jmarshall.com/easy/http/
17
; "Hypertext Transfer Protocol -- HTTP/1.1", http://tools.ietf.org/html/rfc2616
18
 
19
 
20
        URLMAXLEN       = 65535
21
        BUFFERSIZE      = 4096
22
 
23
        __DEBUG__       = 1
24
        __DEBUG_LEVEL__ = 1
25
 
26
 
27
format MS COFF
28
 
29
public @EXPORT as 'EXPORTS'
30
 
31
include '../../../struct.inc'
32
include '../../../proc32.inc'
33
include '../../../macros.inc'
34
purge section,mov,add,sub
35
include '../../../debug-fdo.inc'
36
 
37
include '../../../network.inc'
38
include 'http.inc'
39
 
40
virtual at 0
41
        http_msg http_msg
42
end virtual
43
 
44
macro copy_till_zero {
45
  @@:
46
        lodsb
47
        test    al, al
48
        jz      @f
49
        stosb
50
        jmp     @r
51
  @@:
52
}
53
 
4167 hidnplayr 54
macro HTTP_init_buffer buffer, socketnum {
55
 
56
        mov     eax, buffer
57
        push    socketnum
58
        popd    [eax + http_msg.socket]
59
        lea     esi, [eax + http_msg.data]
60
        mov     [eax + http_msg.flags], 0
61
        mov     [eax + http_msg.write_ptr], esi
62
        mov     [eax + http_msg.buffer_length], BUFFERSIZE -  http_msg.data
63
        mov     [eax + http_msg.chunk_ptr], 0
64
 
65
        mov     [eax + http_msg.status], 0
66
        mov     [eax + http_msg.header_length], 0
67
        mov     [eax + http_msg.content_length], 0
68
}
69
 
4158 hidnplayr 70
section '.flat' code readable align 16
71
 
72
;;===========================================================================;;
73
lib_init: ;//////////////////////////////////////////////////////////////////;;
74
;;---------------------------------------------------------------------------;;
75
;? Library entry point (called after library load)                           ;;
76
;;---------------------------------------------------------------------------;;
77
;> eax = pointer to memory allocation routine                                ;;
78
;> ebx = pointer to memory freeing routine                                   ;;
79
;> ecx = pointer to memory reallocation routine                              ;;
80
;> edx = pointer to library loading routine                                  ;;
81
;;---------------------------------------------------------------------------;;
82
;< eax = 1 (fail) / 0 (ok) (library initialization result)                   ;;
83
;;===========================================================================;;
84
        mov     [mem.alloc], eax
85
        mov     [mem.free], ebx
86
        mov     [mem.realloc], ecx
87
        mov     [dll.load], edx
88
 
89
        invoke  dll.load, @IMPORT
90
        or      eax, eax
91
        jz      .ok
92
 
93
; load proxy settings
94
        invoke  ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr
95
        invoke  ini.get_int, inifile, sec_proxy, key_proxyport, 80
96
        mov     [proxyPort], eax
97
        invoke  ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser
98
        invoke  ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword
99
 
100
        xor     eax, eax
101
        inc     eax
102
        ret
103
 
104
  .ok:
105
        xor     eax, eax
106
        ret
107
 
108
 
109
 
110
 
111
 
112
;;================================================================================================;;
113
proc HTTP_get URL ;///////////////////////////////////////////////////////////////////////////////;;
114
;;------------------------------------------------------------------------------------------------;;
115
;?                                                                                                ;;
116
;;------------------------------------------------------------------------------------------------;;
117
;> _                                                                                              ;;
118
;;------------------------------------------------------------------------------------------------;;
119
;< eax = 0 (error) / buffer ptr                                                                   ;;
120
;;================================================================================================;;
121
locals
122
        hostname        dd ?
123
        pageaddr        dd ?
124
        sockaddr        dd ?
125
        socketnum       dd ?
126
        buffer          dd ?
4167 hidnplayr 127
        port            dd ?
4158 hidnplayr 128
endl
129
 
130
; split the URL into hostname and pageaddr
131
        stdcall parse_url, [URL]
132
        test    eax, eax
133
        jz      .error
134
        mov     [hostname], eax
135
        mov     [pageaddr], ebx
136
 
137
; Do we need to use a proxy?
138
        cmp     [proxyAddr], 0
139
        jne     .proxy_done
140
 
141
  .proxy_done:
142
 
4167 hidnplayr 143
;;;;
144
        mov     [port], 80      ;;;; FIXME
145
 
146
; Connect to the other side.
147
        stdcall open_connection, [hostname], [port]
4158 hidnplayr 148
        test    eax, eax
4167 hidnplayr 149
        jz      .error
150
        mov     [socketnum], eax
4158 hidnplayr 151
 
4167 hidnplayr 152
; Create the HTTP request.
153
        invoke  mem.alloc, BUFFERSIZE
4158 hidnplayr 154
        test    eax, eax
155
        jz      .error
4167 hidnplayr 156
        mov     [buffer], eax
157
        mov     edi, eax
158
        DEBUGF  1, "Buffer has been allocated.\n"
4158 hidnplayr 159
 
4167 hidnplayr 160
        mov     esi, str_get
161
        copy_till_zero
4158 hidnplayr 162
 
4167 hidnplayr 163
        mov     esi, [pageaddr]
164
        copy_till_zero
4158 hidnplayr 165
 
4167 hidnplayr 166
        mov     esi, str_http11
167
        mov     ecx, str_http11.length
168
        rep     movsb
169
 
170
        mov     esi, [hostname]
171
        copy_till_zero
172
 
173
        mov     esi, str_close
174
        mov     ecx, str_close.length
175
        rep     movsb
176
 
177
        mov     byte[edi], 0
178
        DEBUGF  1, "Request:\n%s", [buffer]
179
 
180
; Send the request
181
        mov     esi, edi
182
        sub     esi, [buffer]   ; length
183
        xor     edi, edi        ; flags
184
 
185
        mcall   send, [socketnum], [buffer]
4158 hidnplayr 186
        test    eax, eax
187
        jz      .error
4167 hidnplayr 188
        DEBUGF  1, "Request has been sent to server.\n"
4158 hidnplayr 189
 
4167 hidnplayr 190
        HTTP_init_buffer [buffer], [socketnum]
191
 
192
        ret                     ; return buffer ptr
193
 
194
  .error:
195
        DEBUGF  1, "Error!\n"
196
        xor     eax, eax        ; return 0 = error
197
        ret
198
 
199
endp
200
 
201
 
202
 
203
;;================================================================================================;;
204
proc HTTP_head URL ;///////////////////////////////////////////////////////////////////////////////;;
205
;;------------------------------------------------------------------------------------------------;;
206
;?                                                                                                ;;
207
;;------------------------------------------------------------------------------------------------;;
208
;> _                                                                                              ;;
209
;;------------------------------------------------------------------------------------------------;;
210
;< eax = 0 (error) / buffer ptr                                                                   ;;
211
;;================================================================================================;;
212
locals
213
        hostname        dd ?
214
        pageaddr        dd ?
215
        sockaddr        dd ?
216
        socketnum       dd ?
217
        buffer          dd ?
218
        port            dd ?
219
endl
220
 
221
; split the URL into hostname and pageaddr
222
        stdcall parse_url, [URL]
4158 hidnplayr 223
        test    eax, eax
4167 hidnplayr 224
        jz      .error
225
        mov     [hostname], eax
226
        mov     [pageaddr], ebx
4158 hidnplayr 227
 
4167 hidnplayr 228
; Do we need to use a proxy?
229
        cmp     [proxyAddr], 0
230
        jne     .proxy_done
4158 hidnplayr 231
 
4167 hidnplayr 232
        ; TODO: set hostname to that of the
233
  .proxy_done:
234
 
235
;;;;
236
        mov     [port], 80      ;;;; FIXME
237
 
238
; Connect to the other side.
239
        stdcall open_connection, [hostname], [port]
240
        test    eax, eax
241
        jz      .error
242
        mov     [socketnum], eax
243
 
4158 hidnplayr 244
; Create the HTTP request.
245
        invoke  mem.alloc, BUFFERSIZE
246
        test    eax, eax
247
        jz      .error
248
        mov     [buffer], eax
4167 hidnplayr 249
        mov     edi, eax
4158 hidnplayr 250
        DEBUGF  1, "Buffer has been allocated.\n"
251
 
4167 hidnplayr 252
        mov     esi, str_head
4158 hidnplayr 253
        copy_till_zero
254
 
4167 hidnplayr 255
        mov     esi, [pageaddr]
256
        copy_till_zero
257
 
4158 hidnplayr 258
        mov     esi, str_http11
259
        mov     ecx, str_http11.length
260
        rep     movsb
261
 
262
        mov     esi, [hostname]
263
        copy_till_zero
264
 
265
        mov     esi, str_close
266
        mov     ecx, str_close.length
267
        rep     movsb
268
 
269
        mov     byte[edi], 0
270
        DEBUGF  1, "Request:\n%s", [buffer]
271
 
4167 hidnplayr 272
; Send the request
4158 hidnplayr 273
        mov     esi, edi
274
        sub     esi, [buffer]   ; length
275
        xor     edi, edi        ; flags
276
 
277
        mcall   send, [socketnum], [buffer]
278
        test    eax, eax
279
        jz      .error
280
        DEBUGF  1, "Request has been sent to server.\n"
281
 
4167 hidnplayr 282
        HTTP_init_buffer [buffer], [socketnum]
4158 hidnplayr 283
 
4167 hidnplayr 284
        ret                     ; return buffer ptr
4158 hidnplayr 285
 
4167 hidnplayr 286
  .error:
287
        DEBUGF  1, "Error!\n"
288
        xor     eax, eax        ; return 0 = error
289
        ret
290
 
291
endp
292
 
293
 
294
;;================================================================================================;;
295
proc HTTP_post URL, content, content_type, content_length ;///////////////////////////////////////;;
296
;;------------------------------------------------------------------------------------------------;;
297
;?                                                                                                ;;
298
;;------------------------------------------------------------------------------------------------;;
299
;> _                                                                                              ;;
300
;;------------------------------------------------------------------------------------------------;;
301
;< eax = 0 (error) / buffer ptr                                                                   ;;
302
;;================================================================================================;;
303
locals
304
        hostname        dd ?
305
        pageaddr        dd ?
306
        sockaddr        dd ?
307
        socketnum       dd ?
308
        buffer          dd ?
309
        port            dd ?
310
endl
311
 
312
; split the URL into hostname and pageaddr
313
        stdcall parse_url, [URL]
314
        test    eax, eax
315
        jz      .error
316
        mov     [hostname], eax
317
        mov     [pageaddr], ebx
318
 
319
; Do we need to use a proxy?
320
        cmp     [proxyAddr], 0
321
        jne     .proxy_done
322
 
323
        ; TODO: set hostname to that of the
324
  .proxy_done:
325
 
326
;;;;
327
        mov     [port], 80      ;;;; FIXME
328
 
329
; Connect to the other side.
330
        stdcall open_connection, [hostname], [port]
331
        test    eax, eax
332
        jz      .error
333
        mov     [socketnum], eax
334
 
335
; Create the HTTP request.
336
        invoke  mem.alloc, BUFFERSIZE
337
        test    eax, eax
338
        jz      .error
339
        mov     [buffer], eax
340
        mov     edi, eax
341
        DEBUGF  1, "Buffer has been allocated.\n"
342
 
343
        mov     esi, str_post
344
        copy_till_zero
345
 
346
        mov     esi, [pageaddr]
347
        copy_till_zero
348
 
349
        mov     esi, str_http11
350
        mov     ecx, str_http11.length
351
        rep     movsb
352
 
353
        mov     esi, [hostname]
354
        copy_till_zero
355
 
356
        mov     esi, str_post_cl
357
        mov     ecx, str_post_cl.length
358
        rep     movsb
359
 
360
        mov     eax, [content_length]
361
        call    ascii_dec
362
 
363
        mov     esi, str_post_ct
364
        mov     ecx, str_post_ct.length
365
        rep     movsb
366
 
367
        mov     esi, [content_type]
368
        rep     movsb
369
 
370
        mov     esi, str_close
371
        mov     ecx, str_close.length
372
        rep     movsb
373
 
374
        mov     byte[edi], 0
375
        DEBUGF  1, "Request:\n%s", [buffer]
376
 
377
; Send the request
378
        mov     esi, edi
379
        sub     esi, [buffer]   ; length
380
        xor     edi, edi        ; flags
381
        mcall   send, [socketnum], [buffer]
382
        test    eax, eax
383
        jz      .error
384
        DEBUGF  1, "Request has been sent to server.\n"
385
 
386
        mcall   send, [socketnum], [content], [content_length]
387
        test    eax, eax
388
        jz      .error
389
        DEBUGF  1, "Data has been sent to server.\n"
390
 
391
        HTTP_init_buffer [buffer], [socketnum]
392
;        mov     eax, [buffer]
393
 
4158 hidnplayr 394
        ret                     ; return buffer ptr
395
 
396
  .error:
397
        DEBUGF  1, "Error!\n"
398
        xor     eax, eax        ; return 0 = error
399
        ret
400
 
401
endp
402
 
403
 
404
 
405
;;================================================================================================;;
406
proc HTTP_process identifier ;////////////////////////////////////////////////////////////////////;;
407
;;------------------------------------------------------------------------------------------------;;
408
;?                                                                                                ;;
409
;;------------------------------------------------------------------------------------------------;;
410
;> _                                                                                              ;;
411
;;------------------------------------------------------------------------------------------------;;
412
;< eax = -1 (not finished) / 0 finished                                                           ;;
413
;;================================================================================================;;
414
        pusha
415
        mov     ebp, [identifier]
4162 hidnplayr 416
 
417
; Receive some data
4158 hidnplayr 418
        mcall   recv, [ebp + http_msg.socket], [ebp + http_msg.write_ptr], \
419
                      [ebp + http_msg.buffer_length], MSG_DONTWAIT
420
        cmp     eax, 0xffffffff
421
        je      .check_socket
422
        DEBUGF  1, "Received %u bytes\n", eax
423
 
4162 hidnplayr 424
; Update pointers
4158 hidnplayr 425
        mov     edi, [ebp + http_msg.write_ptr]
426
        add     [ebp + http_msg.write_ptr], eax
427
        sub     [ebp + http_msg.buffer_length], eax
428
        jz      .got_all_data
4162 hidnplayr 429
 
430
; If data is chunked, combine chunks into contiguous data.
431
        test    [ebp + http_msg.flags], FLAG_CHUNKED
432
        jnz     .chunk_loop
433
 
434
; Did we detect the header yet?
4158 hidnplayr 435
        test    [ebp + http_msg.flags], FLAG_GOT_HEADER
436
        jnz     .header_parsed
437
 
4162 hidnplayr 438
; We havent found the header yet, search for it..
4158 hidnplayr 439
        sub     eax, 4
4162 hidnplayr 440
        jl      .need_more_data
4158 hidnplayr 441
  .scan:
442
        ; scan for end of header (empty line)
443
        cmp     dword[edi], 0x0a0d0a0d                  ; end of header
444
        je      .end_of_header
445
        cmp     word[edi+2], 0x0a0a
446
        je      .end_of_header
447
        inc     edi
448
        dec     eax
449
        jnz     .scan
450
 
451
  .end_of_header:
452
        add     edi, 4 - http_msg.data
453
        sub     edi, ebp
454
        mov     [ebp + http_msg.header_length], edi
455
        or      [ebp + http_msg.flags], FLAG_GOT_HEADER
456
        DEBUGF  1, "Header length: %u\n", edi
457
 
458
; Ok, we have found header:
459
        cmp     dword[ebp + http_msg.data], 'HTTP'
460
        jne     .invalid_header
461
        cmp     dword[ebp + http_msg.data+4], '/1.0'
462
        je      .http_1.0
463
        cmp     dword[ebp + http_msg.data+4], '/1.1'
464
        jne     .invalid_header
465
        or      [ebp + http_msg.flags], FLAG_HTTP11
466
  .http_1.0:
467
        cmp     byte[ebp + http_msg.data+8], ' '
468
        jne     .invalid_header
469
        DEBUGF  1, "Header seems valid.\n"
470
 
471
        lea     esi, [ebp + http_msg.data+9]
472
        xor     eax, eax
473
        xor     ebx, ebx
474
        mov     ecx, 3
475
  .statusloop:
476
        lodsb
477
        sub     al, '0'
478
        jb      .invalid_header
479
        cmp     al, 9
480
        ja      .invalid_header
481
        lea     ebx, [ebx + 4*ebx]
482
        shl     ebx, 1
483
        add     ebx, eax
484
        dec     ecx
485
        jnz     .statusloop
486
        mov     [ebp + http_msg.status], ebx
487
        DEBUGF  1, "Status: %u\n", ebx
488
 
489
; Now, convert all header names to lowercase.
490
; This way, it will be much easier to find certain header fields, later on.
491
 
492
        lea     esi, [ebp + http_msg.data]
493
        mov     ecx, [ebp + http_msg.header_length]
494
  .need_newline:
495
        inc     esi
496
        dec     ecx
497
        jz      .convert_done
498
        cmp     byte[esi], 10
499
        jne     .need_newline
500
; Ok, we have a newline, a line beginning with space or tabs has no header fields.
501
 
502
        inc     esi
503
        dec     ecx
504
        jz      .convert_done
505
        cmp     byte[esi], ' '
506
        je      .need_newline
507
        cmp     byte[esi], 9    ; horizontal tab
508
        je      .need_newline
509
        jmp     .convert_loop
510
  .next_char:
511
        inc     esi
512
        dec     ecx
513
        jz      .convert_done
514
  .convert_loop:
515
        cmp     byte[esi], ':'
516
        je      .need_newline
517
        cmp     byte[esi], 'A'
518
        jb      .next_char
519
        cmp     byte[esi], 'Z'
520
        ja      .next_char
521
        or      byte[esi], 0x20 ; convert to lowercase
522
        jmp     .next_char
523
  .convert_done:
524
        mov     byte[esi-1], 0
525
        lea     esi, [ebp + http_msg.data]
526
        DEBUGF  1, "Header names converted to lowercase:\n%s\n", esi
527
 
528
; Check for content-length header field.
529
        stdcall find_header_field, ebp, str_cl
530
        test    eax, eax
531
        jz      .no_content
532
        or      [ebp + http_msg.flags], FLAG_CONTENT_LENGTH
533
 
534
        xor     edx, edx
535
  .cl_loop:
536
        movzx   ebx, byte[eax]
537
        inc     eax
538
        cmp     bl, 10
539
        je      .cl_ok
540
        cmp     bl, 13
541
        je      .cl_ok
542
        cmp     bl, ' '
543
        je      .cl_ok
544
        sub     bl, '0'
545
        jb      .invalid_header
546
        cmp     bl, 9
547
        ja      .invalid_header
548
        lea     edx, [edx + edx*4]      ; edx = edx*10
549
        shl     edx, 1                  ;
550
        add     edx, ebx
551
        jmp     .cl_loop
552
 
553
  .cl_ok:
554
        mov     [ebp + http_msg.content_length], edx
555
        DEBUGF  1, "Content-length: %u\n", edx
556
 
557
; Resize buffer according to content-length.
558
        mov     eax, [ebp + http_msg.header_length]
559
        add     eax, [ebp + http_msg.content_length]
560
        add     eax, http_msg.data
561
 
562
        mov     ecx, eax
563
        sub     ecx, [ebp + http_msg.write_ptr]
564
        mov     [ebp + http_msg.buffer_length], ecx
565
 
566
        invoke  mem.realloc, ebp, eax
567
        or      eax, eax
568
        jz      .no_ram
569
        jmp     .header_parsed  ; hooray!
570
 
571
  .no_content:
572
        DEBUGF  1, "Content-length not found.\n"
573
 
574
; We didnt find 'content-length', maybe server is using chunked transfer encoding?
575
; Try to find 'transfer-encoding' header.
576
        stdcall find_header_field, ebp, str_te
577
        test    eax, eax
578
        jz      .invalid_header
579
 
580
        mov     ebx, dword[eax]
4162 hidnplayr 581
        or      ebx, 0x20202020
4158 hidnplayr 582
        cmp     ebx, 'chun'
583
        jne     .invalid_header
584
        mov     ebx, dword[eax+4]
4162 hidnplayr 585
        or      ebx, 0x00202020
586
        and     ebx, 0x00ffffff
4158 hidnplayr 587
        cmp     ebx, 'ked'
588
        jne     .invalid_header
589
 
590
        or      [ebp + http_msg.flags], FLAG_CHUNKED
591
        DEBUGF  1, "Transfer type is: chunked\n"
592
 
593
; Set chunk pointer where first chunk should begin.
4162 hidnplayr 594
        lea     eax, [ebp + http_msg.data]
595
        add     eax, [ebp + http_msg.header_length]
4158 hidnplayr 596
        mov     [ebp + http_msg.chunk_ptr], eax
597
 
4162 hidnplayr 598
  .chunk_loop:
4158 hidnplayr 599
        mov     ecx, [ebp + http_msg.write_ptr]
600
        sub     ecx, [ebp + http_msg.chunk_ptr]
4162 hidnplayr 601
        jb      .need_more_data_chunked
4158 hidnplayr 602
 
4162 hidnplayr 603
; TODO: make sure we have the complete chunkline header
4158 hidnplayr 604
        mov     esi, [ebp + http_msg.chunk_ptr]
605
        xor     ebx, ebx
606
  .chunk_hexloop:
607
        lodsb
608
        sub     al, '0'
609
        jb      .chunk_
610
        cmp     al, 9
611
        jbe     .chunk_hex
4162 hidnplayr 612
        sub     al, 'A' - '0' - 10
4158 hidnplayr 613
        jb      .chunk_
4162 hidnplayr 614
        cmp     al, 15
4158 hidnplayr 615
        jbe     .chunk_hex
616
        sub     al, 'a' - 'A'
4162 hidnplayr 617
        cmp     al, 15
4158 hidnplayr 618
        ja      .chunk_
619
  .chunk_hex:
620
        shl     ebx, 4
621
        add     bl, al
622
        jmp     .chunk_hexloop
623
  .chunk_:
624
        DEBUGF  1, "got chunk of %u bytes\n", ebx
625
; If chunk size is 0, all chunks have been received.
626
        test    ebx, ebx
4162 hidnplayr 627
        jz      .got_all_data_chunked           ; last chunk, hooray! FIXME: what if it wasnt a valid hex number???
628
        mov     edi, [ebp + http_msg.chunk_ptr] ; we'll need this in about 25 lines...
4158 hidnplayr 629
        add     [ebp + http_msg.chunk_ptr], ebx
630
 
631
; Chunkline ends with a CR, LF or simply LF
632
  .end_of_chunkline?:           ; FIXME: buffer overflow possible!
633
        cmp     al, 10
634
        je      .end_of_chunkline
635
        lodsb
636
        jmp     .end_of_chunkline?
637
 
638
  .end_of_chunkline:
4162 hidnplayr 639
; Realloc buffer, make it 'chunksize' bigger.
640
        mov     eax, [ebp + http_msg.buffer_length]
641
        add     eax, ebx
642
        invoke  mem.realloc, ebp, eax
643
        or      eax, eax
644
        jz      .no_ram
645
        add     [ebp + http_msg.buffer_length], ebx
646
 
647
; Update write ptr
648
        mov     eax, esi
649
        sub     eax, edi
650
        sub     [ebp + http_msg.write_ptr], eax
651
 
4158 hidnplayr 652
; Now move all received data to the left (remove chunk header).
4162 hidnplayr 653
; Update content_length accordingly.
4158 hidnplayr 654
        mov     ecx, [ebp + http_msg.write_ptr]
655
        sub     ecx, esi
656
        add     [ebp + http_msg.content_length], ecx
657
        rep     movsb
4162 hidnplayr 658
        jmp     .chunk_loop
4158 hidnplayr 659
 
660
; Check if we got all the data.
4162 hidnplayr 661
  .header_parsed:
4158 hidnplayr 662
        mov     eax, [ebp + http_msg.header_length]
663
        add     eax, [ebp + http_msg.content_length]
664
        cmp     eax, [ebp + http_msg.buffer_length]
665
        je      .got_all_data
4162 hidnplayr 666
  .need_more_data:
667
        popa
668
        xor     eax, eax
669
        dec     eax
670
        ret
4158 hidnplayr 671
 
4162 hidnplayr 672
  .need_more_data_chunked:
673
        add     [ebp + http_msg.content_length], eax
4158 hidnplayr 674
        popa
675
        xor     eax, eax
676
        dec     eax
677
        ret
678
 
4162 hidnplayr 679
  .got_all_data_chunked:
680
        mov     eax, [ebp + http_msg.chunk_ptr]
681
        sub     eax, [ebp + http_msg.header_length]
682
        sub     eax, http_msg.data
683
        sub     eax, ebp
684
        mov     [ebp + http_msg.content_length], eax
4158 hidnplayr 685
  .got_all_data:
4162 hidnplayr 686
        DEBUGF  1, "We got all the data! (%u bytes)\n", [ebp + http_msg.content_length]
4158 hidnplayr 687
        or      [ebp + http_msg.flags], FLAG_GOT_DATA
688
        mcall   close, [ebp + http_msg.socket]
689
        popa
690
        xor     eax, eax
691
        ret
692
 
693
  .check_socket:
694
        cmp     ebx, EWOULDBLOCK
4162 hidnplayr 695
        je      .need_more_data
4158 hidnplayr 696
        DEBUGF  1, "ERROR: socket error %u\n", ebx
697
 
698
        or      [ebp + http_msg.flags], FLAG_SOCKET_ERROR
699
        popa
700
        xor     eax, eax
701
        ret
702
 
703
  .invalid_header:
704
        DEBUGF  1, "ERROR: invalid header\n"
705
        or      [ebp + http_msg.flags], FLAG_INVALID_HEADER
706
        popa
707
        xor     eax, eax
708
        ret
709
 
710
  .no_ram:
711
        DEBUGF  1, "ERROR: out of RAM\n"
712
        or      [ebp + http_msg.flags], FLAG_NO_RAM
713
        popa
714
        xor     eax, eax
715
        ret
716
 
717
endp
718
 
719
 
720
 
721
;;================================================================================================;;
722
proc find_header_field identifier, headername ;///////////////////////////////////////////////////;;
723
;;------------------------------------------------------------------------------------------------;;
724
;?                                                                                                ;;
725
;;------------------------------------------------------------------------------------------------;;
726
;> _                                                                                              ;;
727
;;------------------------------------------------------------------------------------------------;;
728
;< eax = -1 (error) / 0                                                                           ;;
729
;;================================================================================================;;
730
        push    ebx ecx edx esi edi
731
 
732
        DEBUGF  1, "Find header field: %s\n", [headername]
733
 
734
        mov     ebx, [identifier]
735
        lea     edx, [ebx + http_msg.data]
736
        mov     ecx, edx
737
        add     ecx, [ebx + http_msg.header_length]
738
 
739
  .restart:
740
        mov     esi, [headername]
741
        mov     edi, edx
742
  .loop:
743
        cmp     edi, ecx
744
        jae     .fail
745
        lodsb
746
        scasb
747
        je      .loop
748
        test    al, al
749
        jz      .done?
750
  .next:
751
        inc     edx
752
        jmp     .restart
753
 
754
  .not_done:
755
        inc     edi
756
  .done?:
757
        cmp     byte[edi-1], ':'
758
        je      .almost_done
759
        cmp     byte[edi-1], ' '
760
        je      .not_done
761
        cmp     byte[edi-1], 9  ; tab
762
        je      .not_done
763
 
764
        jmp     .next
765
 
766
  .almost_done:                 ; FIXME: buffer overflow?
767
        dec     edi
768
        DEBUGF  1, "Found header field\n"
769
  .spaceloop:
770
        inc     edi
771
        cmp     byte[edi], ' '
772
        je      .spaceloop
773
        cmp     byte[edi], 9    ; tab
774
        je      .spaceloop
775
 
776
        mov     eax, edi
777
        pop     edi esi edx ecx ebx
778
        ret
779
 
780
  .fail:
781
        pop     edi esi edx ecx ebx
782
        xor     eax, eax
783
        ret
784
 
785
endp
786
 
787
 
788
; internal procedures start here:
789
 
4167 hidnplayr 790
;;================================================================================================;;
791
proc open_connection hostname, port ;/////////////////////////////////////////////////////////////;;
792
;;------------------------------------------------------------------------------------------------;;
793
;?                                                                                                ;;
794
;;------------------------------------------------------------------------------------------------;;
795
;> _                                                                                              ;;
796
;;------------------------------------------------------------------------------------------------;;
797
;< eax = -1 (error) / 0                                                                           ;;
798
;;================================================================================================;;
4158 hidnplayr 799
 
4167 hidnplayr 800
locals
801
        sockaddr        dd ?
802
        socketnum       dd ?
803
endl
804
 
805
; Resolve the hostname
806
        DEBUGF  1, "Resolving hostname\n"
807
        push    esp     ; reserve stack place
808
        push    esp     ; fourth parameter
809
        push    0       ; third parameter
810
        push    0       ; second parameter
811
        push    [hostname]
812
        call    [getaddrinfo]
813
        pop     esi
814
        test    eax, eax
815
        jnz     .error1
816
 
817
; getaddrinfo returns addrinfo struct, make the pointer to sockaddr struct
818
        mov     esi, [esi + addrinfo.ai_addr]
819
        mov     [sockaddr], esi
820
        mov     eax, [esi + sockaddr_in.sin_addr]
821
        test    eax, eax
822
        jz      .error2
823
 
824
        DEBUGF  1, "Server ip=%u.%u.%u.%u\n", \
825
        [esi + sockaddr_in.sin_addr]:1, [esi + sockaddr_in.sin_addr + 1]:1, \
826
        [esi + sockaddr_in.sin_addr + 2]:1, [esi + sockaddr_in.sin_addr + 3]:1
827
 
828
        mov     [esi + sockaddr_in.sin_family], AF_INET4
829
        mov     eax, [port]
830
        xchg    al, ah
831
        mov     [esi + sockaddr_in.sin_port], ax
832
 
833
; Connect to the server.
834
        mcall   socket, AF_INET4, SOCK_STREAM, 0
835
        test    eax, eax
836
        jz      .error2
837
        mov     [socketnum], eax
838
        DEBUGF  1, "Socket: 0x%x\n", eax
839
 
840
        mcall   connect, [socketnum], [sockaddr], 18
841
        test    eax, eax
842
        jnz     .error2
843
        DEBUGF  1, "Socket is now connected.\n"
844
 
845
; free allocated memory
846
        push    [sockaddr]
847
        call    [freeaddrinfo]
848
 
849
        mov     eax, [socketnum]
850
        ret
851
 
852
  .error2:
853
 
854
; free allocated memory
855
        push    [sockaddr]
856
        call    [freeaddrinfo]
857
 
858
  .error1:
859
        xor     eax, eax
860
        ret
861
 
862
endp
863
 
864
 
4158 hidnplayr 865
;;================================================================================================;;
866
proc parse_url URL ;//////////////////////////////////////////////////////////////////////////////;;
867
;;------------------------------------------------------------------------------------------------;;
868
;?                                                                                                ;;
869
;;------------------------------------------------------------------------------------------------;;
870
;> _                                                                                              ;;
871
;;------------------------------------------------------------------------------------------------;;
872
;< eax = -1 (error) / 0                                                                           ;;
873
;;================================================================================================;;
874
 
875
locals
876
        urlsize         dd ?
877
        hostname        dd ?
878
        pageaddr        dd ?
879
endl
880
 
4161 hidnplayr 881
        DEBUGF  1, "parsing URL: %s\n", [URL]
4158 hidnplayr 882
 
883
; remove any leading protocol text
884
        mov     esi, [URL]
885
        mov     ecx, URLMAXLEN
886
        mov     ax, '//'
887
  .loop1:
888
        cmp     byte[esi], 0            ; end of URL?
889
        je      .url_ok                 ; yep, so not found
890
        cmp     [esi], ax
891
        je      .skip_proto
892
        inc     esi
893
        dec     ecx
894
        jnz     .loop1
895
 
4161 hidnplayr 896
        DEBUGF  1, "Invalid URL\n"
4158 hidnplayr 897
        xor     eax, eax
898
        ret
899
 
900
  .skip_proto:
901
        inc     esi                     ; skip the two '/'
902
        inc     esi
903
        mov     [URL], esi              ; update pointer so it skips protocol
904
        jmp     .loop1                  ; we still need to find the length of the URL
905
 
906
  .url_ok:
907
        sub     esi, [URL]              ; calculate total length of URL
908
        mov     [urlsize], esi
909
 
910
 
911
; now look for page delimiter - it's a '/' character
912
        mov     ecx, esi                ; URL length
913
        mov     edi, [URL]
914
        mov     al, '/'
915
        repne   scasb
4161 hidnplayr 916
        jne     @f
4158 hidnplayr 917
        dec     edi                     ; return one char, '/' must be part of the pageaddr
918
        inc     ecx                     ;
4161 hidnplayr 919
  @@:
4158 hidnplayr 920
        push    ecx edi                 ; remember the pointer and length of pageaddr
921
 
922
        mov     ecx, edi
923
        sub     ecx, [URL]
924
        inc     ecx                     ; we will add a 0 byte at the end
925
        invoke  mem.alloc, ecx
926
        or      eax, eax
927
        jz      .no_mem
928
 
929
        mov     [hostname], eax         ; copy hostname to buffer
930
        mov     edi, eax
931
        mov     esi, [URL]
932
        dec     ecx
933
        rep     movsb
934
        xor     al, al
935
        stosb
936
 
4161 hidnplayr 937
        mov     [pageaddr], str_slash   ; assume there is no pageaddr
4158 hidnplayr 938
        pop     esi ecx
939
        test    ecx, ecx
940
        jz      .no_page
941
        inc     ecx                     ; we will add a 0 byte at the end
942
        invoke  mem.alloc, ecx
943
        or      eax, eax
944
        jz      .no_mem
945
 
946
        mov     [pageaddr], eax         ; copy pageaddr to buffer
947
        mov     edi, eax
948
        dec     ecx
949
        rep     movsb
950
        xor     al, al
951
        stosb
952
  .no_page:
953
 
954
        mov     eax, [hostname]
955
        mov     ebx, [pageaddr]
956
 
957
        DEBUGF  1, "hostname: %s\n", eax
958
        DEBUGF  1, "pageaddr: %s\n", ebx
959
 
960
        ret
961
 
962
  .no_mem:
963
        xor     eax, eax
964
        ret
965
 
966
endp
967
 
968
 
4167 hidnplayr 969
; in: eax = number
970
;     edi = ptr where to store ascii
971
ascii_dec:
4158 hidnplayr 972
 
4167 hidnplayr 973
        mov     ecx, 10
974
  .loop:
975
        xor     edx, edx
976
        div     ecx
977
        add     dl, '0'
978
        mov     byte[edi], dl
979
        inc     edi
980
        test    eax, eax
981
        jnz     .loop
4158 hidnplayr 982
 
4167 hidnplayr 983
        ret
4158 hidnplayr 984
 
4167 hidnplayr 985
 
4158 hidnplayr 986
;;================================================================================================;;
987
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
988
;;================================================================================================;;
989
;! Imported functions section                                                                     ;;
990
;;================================================================================================;;
991
;;////////////////////////////////////////////////////////////////////////////////////////////////;;
992
;;================================================================================================;;
993
 
994
 
995
align 16
996
@IMPORT:
997
 
998
library \
999
        libini, 'libini.obj', \
1000
        network, 'network.obj'
1001
 
1002
import  libini, \
1003
        ini.get_str, 'ini_get_str', \
1004
        ini.get_int, 'ini_get_int'
1005
 
1006
import  network,\
1007
        getaddrinfo, 'getaddrinfo',\
1008
        freeaddrinfo,  'freeaddrinfo',\
1009
        inet_ntoa, 'inet_ntoa'
1010
 
1011
;;===========================================================================;;
1012
;;///////////////////////////////////////////////////////////////////////////;;
1013
;;===========================================================================;;
1014
;! Exported functions section                                                ;;
1015
;;===========================================================================;;
1016
;;///////////////////////////////////////////////////////////////////////////;;
1017
;;===========================================================================;;
1018
 
1019
 
1020
align 4
1021
@EXPORT:
1022
export  \
1023
        lib_init                , 'lib_init'            , \
1024
        0x00010001              , 'version'             , \
1025
        HTTP_get                , 'get'                 , \
4167 hidnplayr 1026
        HTTP_head               , 'head'                , \
1027
        HTTP_post               , 'post'                , \
4158 hidnplayr 1028
        find_header_field       , 'find_header_field'   , \
1029
        HTTP_process            , 'process'
1030
 
1031
;        HTTP_put                , 'put'                 , \
1032
;        HTTP_delete             , 'delete'              , \
1033
;        HTTP_trace              , 'trace'               , \
1034
;        HTTP_connect            , 'connect'             , \
1035
 
1036
 
1037
 
1038
section '.data' data readable writable align 16
1039
 
1040
inifile         db '/sys/settings/network.ini', 0
1041
 
1042
sec_proxy:
1043
key_proxy       db 'proxy', 0
1044
key_proxyport   db 'port', 0
1045
key_user        db 'user', 0
1046
key_password    db 'password', 0
1047
 
1048
str_http11      db ' HTTP/1.1', 13, 10, 'Host: '
1049
  .length       = $ - str_http11
4167 hidnplayr 1050
str_post_cl     db 13, 10, 'Content-Length: '
1051
  .length       = $ - str_post_cl
1052
str_post_ct     db 13, 10, 'Content-Type: '
1053
  .length       = $ - str_post_ct
4158 hidnplayr 1054
str_close       db 13, 10, 'User-Agent: KolibriOS libHTTP/1.0', 13, 10, 'Connection: Close', 13, 10, 13, 10
1055
  .length       = $ - str_close
1056
str_proxy_auth  db 13, 10, 'Proxy-Authorization: Basic '
1057
  .length       = $ - str_proxy_auth
1058
 
1059
base64_table    db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
1060
                db '0123456789+/'
1061
 
1062
str_cl          db 'content-length', 0
4161 hidnplayr 1063
str_slash       db '/', 0
4158 hidnplayr 1064
str_te          db 'transfer-encoding', 0
4167 hidnplayr 1065
str_get         db 'GET ', 0
1066
str_head        db 'HEAD ', 0
1067
str_post        db 'POST ', 0
4158 hidnplayr 1068
 
1069
include_debug_strings
1070
 
1071
; uninitialized data
1072
mem.alloc       dd ?
1073
mem.free        dd ?
1074
mem.realloc     dd ?
1075
dll.load        dd ?
1076
 
1077
proxyAddr       rb 256
1078
proxyUser       rb 256
1079
proxyPassword   rb 256
1080
proxyPort       dd ?