File: BIGPICTURE.txt

package info (click to toggle)
gatling 0.13-6
  • links: PTS
  • area: main
  • in suites: sid, stretch
  • size: 1,196 kB
  • ctags: 1,115
  • sloc: ansic: 23,805; makefile: 143; sh: 71; perl: 30
file content (113 lines) | stat: -rw-r--r-- 4,570 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
in libowfat, every descriptor has a state associated with it, and it
contains a cookie that is set by gatling.  That cookie is a pointer to a
state gatling uses for the connection.  The libowfat state is invisible
from gatling; the gatling state is called struct http_data and is
defined in gatling.h.

Its most important fields are:

  t (the state for gatling's statemachine, type: enum conntype)
  r (a buffer that holds the incoming request)
  iob (an iob that holds the outgoing data)
  buddy (see below)

r is an array (variable length buffer type defined in libowfat)
iob is a structure from libowfat that holds a linked list of buffers
and/or file descriptors that are supposed to be sent out over a file
descriptor.  You can use iob_send to send it directly, or iob_write to
send it via a write() callback; gatling uses this to send data with SSL
encryption.

For some requests, more than one connection is needed.  FTP has a
control and a data connection.  For these, the descriptor of the other
connection is stored in the buddy member of the http_state.

Here is the state flow for typical requests:

HTTP:
  # main()
  - starts out as HTTPSERVER6 or HTTPSERVER4 (IPv4 vs IPv6).
  - gets a read event if a connection comes in.
  # accept_server_connection()
  - calls accept() and makes a new context for that connection,
    sets its type to HTTPREQUEST

  # main()
  - gets a read event if data comes in.  Reads until it sees a \r\n\r\n
    or the size limit is reached (8192 bytes currently)
    # read events are handled in main() - search for io_canread()
  # handle_read_misc()
  # the \r\n\r\n detection is in header_complete()
  # httpresponse()
  # http_openfile()
  - constructs http response header, adds it with iob_addbuf_free
  - adds file content with iob_addfile 
  - uses io_dontwantread and io_wantwrite to switch state machine to writing

  # main()
  - gets a write event
    # write events are handled in main() - search for io_canwrite()
  # handle_write_misc()
  - calls iob_send() (or iob_write() for SSL mode)
  - repeat from "gets a write event" until all data was written
  - if client indicated HTTP keep-alive, switch back to HTTPREQUEST and
    read mode
    otherwise close connection with cleanup()



HTTP with CGI:
  - same as plain HTTP until inside http_openfile().
  # proxy_connection
  - check for the ".proxy" file and go through the list of regexes set
    on command line with -C and -O to see if the request is a CGI or
    proxy.  Same code used for both.

Now, in addition to the connection from browser to gatling, we need a
second connection from gatling to the proxy server / CGI.  For proxy
mode, we just call socket(), but for CGI we use a "fork slave".  gatling
forks right at the start if CGI mode is enabled, and if we want to
create a CGI process, we do not create it ourselves (to save the
overhead of having to close all the open descriptors) but we send a
message to the "fork slave" we created at the beginning. That process
then forks and execs the CGI and returns the descriptor to the CGI to us.
As part of this message, we also pass the HTTP request header to
the fork slave, which writes it to the CGI.

  # still in proxy_connection
  - create a new context for the connection to the CGI
  - change state of http connection from HTTPREQUEST to HTTPPOST
  - set state of cgi connection to PROXYPOST

if request is a POST:
  - if some POST data came in with the http request:
    - put POST data into cgi_connection->r
    - set cgi_connection->still_to_copy to Content-Length
    - set http_connection->still_to_copy to Content-Length - sizeof(already copied data)
    - io_dontwantread(http_connection), io_wantwrite(cgi_connection)

  # main()
  - receive write event on the cgi connection (PROXYPOST)
  # handle_write_proxypost
  - write data from buddy->r to socket, deduct from still_to_copy


if request is a GET:
  - io_dontwantread(http_connection), io_wantread(cgi_connection)

writemoredata:
  # main()
  - receive read event on the cgi connection (PROXYPOST)
  # handle_read_proxypost()
  # proxy_is_readable()
  - read data from cgi connection into stack buffer
  - malloc a buffer for response header plus buffer contents
  - iob_addbuf_free it to http_connection->iob
  - io_dontwantread(cgi_connection), io_wantwrite(http_connection)

  # main()
  - receive write event on the http connection (HTTPPOST)
  # handle_write_httppost()
  - iob_write/iob_send data to http connection
  - if not done: io_dontwantread(http_connection), io_wantread(cgi_connection), goto writemoredata;