source: ogClient-Git/src/ogClient.py @ 900a1c8

Last change on this file since 900a1c8 was 36b5064, checked in by OpenGnSys Support Team <soporte-og@…>, 5 years ago

#1000 Fix ogClient HTTP length handling

Irina reports that "Partition assistant"/"Asistente de particionado" is
not working. This is happening because ogClient is not reading the full
data ogServer sends when the entire HTTP PDU is larger than 1024.
However, ogClient should read the whole message, reading until read data
length is greater or equal to "Content-Length" header value.

ogClient fails to obtain "Content-Length" value because is looking for
"content-length", be aware of the case sensitivity. It also needs to
take into account the header length because read data length also
includes headers.

This patch updates ogClient to:

1) look for "Content-Length instead of "content-length".

2) compare read date length with content length plus headers

length.

  • Property mode set to 100644
File size: 3.7 KB
Line 
1#
2# Copyright (C) 2020 Soleta Networks <info@soleta.eu>
3#
4# This program is free software: you can redistribute it and/or modify it under
5# the terms of the GNU Affero General Public License as published by the
6# Free Software Foundation, version 3.
7#
8
9import errno
10import select
11import socket
12import time
13import email
14import platform
15from io import StringIO
16
17from src.restRequest import *
18from src.ogRest import *
19from enum import Enum
20
21class State(Enum):
22        CONNECTING = 0
23        RECEIVING = 1
24        FORCE_DISCONNECTED = 2
25
26class ogClient:
27        OG_PATH = '/opt/opengnsys/'
28
29        def __init__(self, config):
30                self.CONFIG = config
31
32                self.mode = self.CONFIG['opengnsys']['mode']
33                if self.mode not in {'virtual', 'live'}:
34                        raise ValueError('Mode not supported.')
35
36                if self.CONFIG['samba']['activate']:
37                        assert('user' in self.CONFIG['samba'])
38                        assert('pass' in self.CONFIG['samba'])
39
40                self.ip = self.CONFIG['opengnsys']['ip']
41                self.port = self.CONFIG['opengnsys']['port']
42                self.ogrest = ogRest(self.CONFIG)
43
44        def get_socket(self):
45                return self.sock
46
47        def get_state(self):
48                return self.state
49
50        def connect(self):
51                print('connecting...')
52                self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
53                self.sock.setblocking(0)
54                self.state = State.CONNECTING
55                self.data = ""
56                self.trailer = False
57                self.content_len = 0
58                self.header_len = 0
59
60                try:
61                        self.sock.connect((self.ip, self.port))
62                except socket.error as err:
63                        if err.errno == errno.EINPROGRESS:
64                                return
65                        elif err.errno == errno.ECONNREFUSED:
66                                return
67
68        def send(self, msg):
69                self.sock.send(bytes(msg, 'utf-8'))
70                return len(msg)
71
72        def connect2(self):
73                try:
74                        self.sock.connect((self.ip, self.port))
75                except socket.error as err:
76                        if err.errno == errno.EISCONN:
77                                print('connected')
78                                self.state = State.RECEIVING
79                        else:
80                                time.sleep(1)
81                                print('connection refused, retrying...')
82                                self.state = State.CONNECTING
83                                self.sock.close()
84                                self.connect()
85
86        def receive(self):
87                try:
88                        data = self.sock.recv(1024).decode('utf-8')
89                except socket.error as err:
90                        data = ''
91                        print('failed to received ' + str(err))
92
93                if len(data) == 0:
94                        self.state = State.CONNECTING
95                        self.sock.close()
96                        self.connect()
97
98                self.data = self.data + data
99                request = restRequest()
100
101                if not self.trailer:
102                        header_len = self.data.find("\r\n")
103                        if header_len > 0:
104                                # https://stackoverflow.com/questions/4685217/parse-raw-http-headers
105                                request_line, headers_alone = self.data.split('\n', 1)
106                                headers = email.message_from_file(StringIO(headers_alone))
107
108                                if 'Content-Length' in headers.keys():
109                                        self.content_len = int(headers['Content-Length'])
110
111                                self.trailer = True
112                                # Add 2 because self.data.find("\r\n") does not count "\r\n" for the length
113                                self.header_len = header_len + 2
114
115                if self.trailer and (len(self.data) >= self.content_len + self.header_len):
116                        request.parser(self.data)
117                        self.ogrest.process_request(request, self)
118
119                        # Cleanup state information from request
120                        self.data = ""
121                        self.content_len = 0
122                        self.header_len = 0
123                        self.trailer = False
124
125        def disconnect(self):
126                self.state = State.FORCE_DISCONNECTED
127                self.sock.shutdown(socket.SHUT_RDWR)
128                self.sock.close()
129
130        def run(self):
131                while 1:
132                        sock = self.get_socket()
133                        state = self.get_state()
134
135                        if state == State.CONNECTING:
136                                readset = [ sock ]
137                                writeset = [ sock ]
138                        elif state == State.FORCE_DISCONNECTED:
139                                return 0
140                        else:
141                                readset = [ sock ]
142                                writeset = [ ]
143
144                        readable, writable, exception = select.select(readset, writeset, [ ])
145                        if state == State.CONNECTING and sock in writable:
146                                self.connect2()
147                        elif state == State.RECEIVING and sock in readable:
148                                self.receive()
149                        else:
150                                print('wrong state, not ever happen!' + str(state))
Note: See TracBrowser for help on using the repository browser.