• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cle-b / httpdbg / 15450598664

04 Jun 2025 06:41PM UTC coverage: 88.618% (-0.07%) from 88.689%
15450598664

push

github

web-flow
fix short stack description for initiator (#195)

8 of 8 new or added lines in 2 files covered. (100.0%)

3 existing lines in 1 file now uncovered.

2071 of 2337 relevant lines covered (88.62%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.12
/httpdbg/hooks/socket.py
1
# -*- coding: utf-8 -*-
2
import asyncio
1✔
3
import asyncio.proactor_events
1✔
4
from collections.abc import Callable
1✔
5
from contextlib import contextmanager
1✔
6
import datetime
1✔
7
import platform
1✔
8
import socket
1✔
9
import ssl
1✔
10
import sys
1✔
11
import traceback
1✔
12
from typing import Generator
1✔
13

14
from httpdbg.hooks.utils import getcallargs
1✔
15
from httpdbg.hooks.utils import decorate
1✔
16
from httpdbg.hooks.utils import undecorate
1✔
17
from httpdbg.initiator import httpdbg_initiator
1✔
18
from httpdbg.records import HTTPRecord
1✔
19
from httpdbg.records import HTTPRecords
1✔
20
from httpdbg.log import logger
1✔
21

22

23
# hook: socket.socket.__init__
24
# what: A new socket object is created.
25
# action: If an entry exists in the temporary raw socket storage list, it is removed.
26
def set_hook_for_socket_init(records: HTTPRecords, method: Callable):
1✔
27
    def hook(self, *args, **kwargs):
1✔
28
        records.del_socket_data(self)
1✔
29

30
        return method(self, *args, **kwargs)
1✔
31

32
    return hook
1✔
33

34

35
# hook: socket.socket.connect, ssl.SSLSocket.connect
36
# what: A connection to a remote socket is initiated.
37
# action: A new entry is added to the temporary raw socket storage list.
38
def set_hook_for_socket_connect(records: HTTPRecords, method: Callable):
1✔
39
    def hook(self, *args, **kwargs):
1✔
40
        tbegin: datetime.datetime = datetime.datetime.now(datetime.timezone.utc)
1✔
41
        socketdata = records.get_socket_data(self, force_new=True)
1✔
42
        if socketdata:
1✔
43
            logger().info(
1✔
44
                f"CONNECT - self={self} id={id(self)} socketdata={socketdata} args={args} kwargs={kwargs}"
45
            )
46
        try:
1✔
47
            r = method(self, *args, **kwargs)
1✔
48
        except Exception as ex:
1✔
49
            if not isinstance(
1✔
50
                ex, (BlockingIOError, OSError)
51
            ):  # BlockingIOError for async, OSError for ipv6
52
                if records.client:
×
53
                    with httpdbg_initiator(
×
54
                        records, traceback.extract_stack(), method, *args, **kwargs
55
                    ) as initiator_and_group:
56
                        initiator, group, is_new = initiator_and_group
×
57
                        if is_new:
×
58
                            initiator.tbegin = tbegin
×
59
                            group.tbegin = tbegin
×
60
                            records.add_new_record_exception(
×
61
                                initiator, group, "http:///", ex
62
                            )
63
            raise
1✔
64

65
        return r
1✔
66

67
    return hook
1✔
68

69

70
# hook: ssl.wrap_socket,
71
# what: Takes an instance sock of socket.socket, and returns an instance of ssl.SSLSocket.
72
# a subtype of socket.socket, which wraps the underlying socket in an SSL context.
73
# action: Link the socket and the sslsocket
74
def set_hook_for_ssl_wrap_socket(records: HTTPRecords, method: Callable):
1✔
75
    def hook(sock, *args, **kwargs):
1✔
76
        tbegin: datetime.datetime = datetime.datetime.now(datetime.timezone.utc)
×
77
        try:
×
78
            sslsocket = method(sock, *args, **kwargs)
×
79
        except Exception as ex:
×
80
            if records.client:
×
81
                with httpdbg_initiator(
×
82
                    records, traceback.extract_stack(), method, *args, **kwargs
83
                ) as initiator_and_group:
84
                    initiator, group, is_new = initiator_and_group
×
85
                    if is_new:
×
86
                        initiator.tbegin = tbegin
×
87
                        group.tbegin = tbegin
×
88
                        records.add_new_record_exception(
×
89
                            initiator, group, "http:///", ex
90
                        )
91
            raise
×
92

93
        logger().info(
×
94
            f"WRAP_SOCKET - {type(sock)}={id(sock)} {type(sslsocket)}={id(sslsocket)}"
95
        )
96

97
        socketdata = records.move_socket_data(sslsocket, sock)
×
98
        if socketdata:
×
99
            logger().info(f"WRAP_SOCKET * - socketdata={socketdata}")
×
100

101
        return sslsocket
×
102

103
    return hook
1✔
104

105

106
# hook: ssl.SSLContext.wrap_socket
107
# what: Wrap an existing Python socket sock and return an instance of SSLContext.sslsocket_class (default SSLSocket).
108
# action: Link the socket and the sslsocket
109
def set_hook_for_sslcontext_wrap_socket(records: HTTPRecords, method: Callable):
1✔
110
    def hook(self, sock, *args, **kwargs):
1✔
111
        tbegin: datetime.datetime = datetime.datetime.now(datetime.timezone.utc)
1✔
112
        try:
1✔
113
            sslsocket = method(self, sock, *args, **kwargs)
1✔
114
        except Exception as ex:
×
115
            if records.client:
×
116
                with httpdbg_initiator(
×
117
                    records, traceback.extract_stack(), method, *args, **kwargs
118
                ) as initiator_and_group:
119
                    initiator, group, is_new = initiator_and_group
×
120
                    if is_new:
×
121
                        initiator.tbegin = tbegin
×
122
                        group.tbegin = tbegin
×
123
                        records.add_new_record_exception(
×
124
                            initiator, group, "http:///", ex
125
                        )
126
            raise
×
127

128
        logger().info(
1✔
129
            f"WRAP_SOCKET (SSLContext) - {type(self)}={id(self)}  {type(sock)}={id(sock)} {type(sslsocket)}={id(sslsocket)}"
130
        )
131

132
        socketdata = records.move_socket_data(sslsocket, sock)
1✔
133
        if socketdata:
1✔
134
            logger().info(f"WRAP_SOCKET (SSLContext) * - socketdata={socketdata}")
×
135

136
        return sslsocket
1✔
137

138
    return hook
1✔
139

140

141
# hook: ssl.SSLContext.wrap_bio
142
# what: Wrap the BIO objects incoming and outgoing and return an instance of SSLContext.sslobject_class (default SSLObject).
143
# action: Record a new SocketRawData if necessary
144
def set_hook_for_socket_wrap_bio(records: HTTPRecords, method: Callable):
1✔
145
    def hook(self, *args, **kwargs):
1✔
146
        tbegin: datetime.datetime = datetime.datetime.now(datetime.timezone.utc)
1✔
147
        try:
1✔
148
            sslobject = method(self, *args, **kwargs)
1✔
149
        except Exception as ex:
×
150
            if records.client:
×
151
                with httpdbg_initiator(
×
152
                    records, traceback.extract_stack(), method, *args, **kwargs
153
                ) as initiator_and_group:
154
                    initiator, group, is_new = initiator_and_group
×
155
                    if is_new:
×
156
                        initiator.tbegin = tbegin
×
157
                        group.tbegin = tbegin
×
158
                        records.add_new_record_exception(
×
159
                            initiator, group, "http:///", ex
160
                        )
161
            raise
×
162

163
        logger().info(
1✔
164
            f"WRAP_SOCKET_BIO - {type(self)}={id(self)} {type(sslobject)}={id(sslobject)}"
165
        )
166

167
        socketdata = records.get_socket_data(sslobject, self)
1✔
168
        if socketdata:
1✔
169
            logger().info(f"WRAP_SOCKET_BIO * - socketdata={socketdata}")
1✔
170

171
        return sslobject
1✔
172

173
    return hook
1✔
174

175

176
# hook: socket.socket.recv_into, ssl.SSLSocket.recv_into, asyncio.proactor_events._ProactorReadPipeTransport._data_received
177
# what: Receive up to nbytes bytes from the socket, storing the data into a buffer rather than creating a new bytestring.
178
# action: Append the data to an existing SocketRawData
179
def set_hook_for_socket_recv_into(records: HTTPRecords, method: Callable):
1✔
180
    def hook(self, buffer, *args, **kwargs):
1✔
181
        socketdata = records.get_socket_data(self)
1✔
182
        if socketdata:
1✔
183
            logger().info(
1✔
184
                f"RECV_INTO - self={self} id={id(self)} socketdata={socketdata} args={args} kwargs={kwargs}"
185
            )
186

187
        nbytes = method(self, buffer, *args, **kwargs)
1✔
188

189
        if buffer:  # it appears that the buffer may be None (observed on Windows).
1✔
190
            if socketdata:
1✔
191
                if socketdata.record:
1✔
192
                    logger().info(
1✔
193
                        f"RECV_INTO (after) - id={id(self)} buffer={(b''+buffer)[:20]}"
194
                    )
195
                    socketdata.record.receive_data(buffer[:nbytes])
1✔
196
                else:
197
                    socketdata.rawdata += buffer[:nbytes]
1✔
198
                    http_detected = socketdata.http_detected()
1✔
199
                    if http_detected:
1✔
200
                        logger().info("RECV_INTO - http detected")
1✔
201
                        logger().info(
1✔
202
                            f"RECV_INTO (after) - id={id(self)} buffer={(b''+buffer)[:20]}"
203
                        )
204
                        with httpdbg_initiator(
1✔
205
                            records,
206
                            traceback.extract_stack(),
207
                            method,
208
                            self,
209
                            buffer,
210
                            *args,
211
                            **kwargs,
212
                        ) as initiator_and_group:
213
                            initiator, group, is_new = initiator_and_group
1✔
214
                            if is_new:
1✔
215
                                tbegin = socketdata.tbegin - datetime.timedelta(
1✔
216
                                    milliseconds=1
217
                                )
218
                                initiator.tbegin = tbegin
1✔
219
                                group.tbegin = tbegin
1✔
220
                            socketdata.record = HTTPRecord(
1✔
221
                                records.current_initiator,
222
                                records.current_group,
223
                                records.current_tag,
224
                                tbegin=socketdata.tbegin,
225
                                is_client=False,
226
                            )
227
                            socketdata.record.address = socketdata.address
1✔
228
                            socketdata.record.ssl = socketdata.ssl
1✔
229
                            socketdata.record.receive_data(socketdata.rawdata)
1✔
230
                            if records.server:
1✔
231
                                records.requests[socketdata.record.id] = (
1✔
232
                                    socketdata.record
233
                                )
234
                    elif http_detected is False:  # if None, there is nothing to do
1✔
235
                        records._sockets[id(self)] = None
×
236

237
        return nbytes
1✔
238

239
    return hook
1✔
240

241

242
# hook: socket.socket.recv, ssl.SSLSocket.recv
243
# what: Receive data from the socket. The return value is a bytes object representing the data received.
244
# action: Append the data to an existing SocketRawData
245
def set_hook_for_socket_recv(records: HTTPRecords, method: Callable):
1✔
246
    def hook(self, bufsize, *args, **kwargs):
1✔
247
        socketdata = records.get_socket_data(self)
1✔
248
        if socketdata:
1✔
249
            logger().info(
1✔
250
                f"RECV - self={self} id={id(self)} socketdata={socketdata} bufsize={bufsize} args={args} kwargs={kwargs}"
251
            )
252

253
        buffer = method(self, bufsize, *args, **kwargs)
1✔
254

255
        if socketdata:
1✔
256
            if socketdata.record:
1✔
257
                socketdata.record.receive_data(buffer)
1✔
258
            else:
259
                socketdata.rawdata += buffer
1✔
260
                http_detected = socketdata.http_detected()
1✔
261
                if http_detected:
1✔
262
                    logger().info("RECV - http detected")
×
263
                    with httpdbg_initiator(
×
264
                        records,
265
                        traceback.extract_stack(),
266
                        method,
267
                        self,
268
                        bufsize,
269
                        *args,
270
                        **kwargs,
271
                    ) as initiator_and_group:
272
                        initiator, group, is_new = initiator_and_group
×
273
                        if is_new:
×
274
                            tbegin = socketdata.tbegin - datetime.timedelta(
×
275
                                milliseconds=1
276
                            )
277
                            initiator.tbegin = tbegin
×
278
                            group.tbegin = tbegin
×
279
                        socketdata.record = HTTPRecord(
×
280
                            records.current_initiator,
281
                            records.current_group,
282
                            records.current_tag,
283
                            tbegin=socketdata.tbegin,
284
                            is_client=False,
285
                        )
286
                        socketdata.record.address = socketdata.address
×
287
                        socketdata.record.ssl = socketdata.ssl
×
288
                        socketdata.record.receive_data(socketdata.rawdata)
×
289
                        if records.server:
×
290
                            records.requests[socketdata.record.id] = socketdata.record
×
291
                elif http_detected is False:  # if None, there is nothing to do
1✔
292
                    records._sockets[id(self)] = None
1✔
293

294
        return buffer
1✔
295

296
    return hook
1✔
297

298

299
# hook: socket.socket.sendall
300
# what: Send data to the socket.
301
# action: Append the data to an existing SocketRawData. Check if this is an HTTP request.
302
# and record it if this is case, otherwise delete the temporay SocketRawData.
303
def set_hook_for_socket_sendall(records: HTTPRecords, method: Callable):
1✔
304
    def hook(self, data, *args, **kwargs):
1✔
305
        socketdata = records.get_socket_data(self, request=True)
1✔
306
        if socketdata:
1✔
307
            logger().info(
1✔
308
                f"SENDALL - self={self} id={id(self)} socketdata={socketdata} data={(b''+bytes(data))[:20]} type={type(data)} args={args} kwargs={kwargs}"
309
            )
310
        if socketdata:
1✔
311
            if socketdata.record:
1✔
312
                socketdata.record.send_data(data)
1✔
313
            else:
314
                socketdata.rawdata += data
1✔
315
                http_detected = socketdata.http_detected()
1✔
316
                if http_detected:
1✔
317
                    logger().info("SENDALL - http detected")
1✔
318
                    with httpdbg_initiator(
1✔
319
                        records,
320
                        traceback.extract_stack(),
321
                        method,
322
                        self,
323
                        data,
324
                        *args,
325
                        **kwargs,
326
                    ) as initiator_and_group:
327
                        initiator, group, is_new = initiator_and_group
1✔
328
                        if is_new:
1✔
329
                            tbegin = socketdata.tbegin - datetime.timedelta(
×
330
                                milliseconds=1
331
                            )
332
                            initiator.tbegin = tbegin
×
333
                            group.tbegin = tbegin
×
334
                        socketdata.record = HTTPRecord(
1✔
335
                            records.current_initiator,
336
                            records.current_group,
337
                            records.current_tag,
338
                            tbegin=socketdata.tbegin,
339
                        )
340
                        socketdata.record.address = socketdata.address
1✔
341
                        socketdata.record.ssl = socketdata.ssl
1✔
342
                        socketdata.record.send_data(socketdata.rawdata)
1✔
343
                        if records.client:
1✔
344
                            records.requests[socketdata.record.id] = socketdata.record
1✔
345
                elif http_detected is False:  # if None, there is nothing to do
1✔
346
                    records._sockets[id(self)] = None
1✔
347

348
        return method(self, data, *args, **kwargs)
1✔
349

350
    return hook
1✔
351

352

353
# hook: socket.socket.send, ssl.SSLSocket.send, asyncio.proactor_events._ProactorBaseWritePipeTransport.write
354
# what: Send data to the socket.
355
# action: Append the data to an existing SocketRawData. Check if this is an HTTP request.
356
# and record it if this is case, otherwise delete the temporay SocketRawData.
357
def set_hook_for_socket_send(records: HTTPRecords, method: Callable):
1✔
358
    def hook(self, data, *args, **kwargs):
1✔
359
        socketdata = records.get_socket_data(self, request=True)
1✔
360
        if socketdata:
1✔
361
            logger().info(
1✔
362
                f"SEND - self={self} id={id(self)} socketdata={socketdata} bytes={(b''+data)[:20]} args={args} kwargs={kwargs}"
363
            )
364

365
        size = method(self, data, *args, **kwargs)
1✔
366

367
        if socketdata:
1✔
368
            if socketdata.record:
1✔
369
                socketdata.record.send_data(data[:size])
1✔
370
            else:
371
                socketdata.rawdata += data[:size]
1✔
372
                http_detected = socketdata.http_detected()
1✔
373
                if http_detected:
1✔
374
                    with httpdbg_initiator(
1✔
375
                        records,
376
                        traceback.extract_stack(),
377
                        method,
378
                        self,
379
                        data,
380
                        *args,
381
                        **kwargs,
382
                    ) as initiator_and_group:
383
                        initiator, group, is_new = initiator_and_group
1✔
384
                        if is_new:
1✔
UNCOV
385
                            tbegin = socketdata.tbegin - datetime.timedelta(
×
386
                                milliseconds=1
387
                            )
UNCOV
388
                            initiator.tbegin = tbegin
×
UNCOV
389
                            group.tbegin = tbegin
×
390
                        socketdata.record = HTTPRecord(
1✔
391
                            records.current_initiator,
392
                            records.current_group,
393
                            records.current_tag,
394
                            tbegin=socketdata.tbegin,
395
                        )
396
                        socketdata.record.address = socketdata.address
1✔
397
                        socketdata.record.ssl = socketdata.ssl
1✔
398
                        socketdata.record.send_data(socketdata.rawdata)
1✔
399
                        if records.client:
1✔
400
                            records.requests[socketdata.record.id] = socketdata.record
1✔
401
                elif http_detected is False:  # if None, there is nothing to do
1✔
402
                    records._sockets[id(self)] = None
1✔
403
        return size
1✔
404

405
    return hook
1✔
406

407

408
# hook: asyncio.BaseEventLoop.create_connection
409
# what: Open a streaming transport connection to a given address specified by host and port.
410
# action: Link the socket and the sslsocket
411
def set_hook_for_asyncio_create_connection(records: HTTPRecords, method: Callable):
1✔
412
    async def hook(self, *args, **kwargs):
1✔
413
        logger().info(
1✔
414
            f"CREATE_CONNECTION - self={self} id={id(self)} args={args} kwargs={kwargs}"
415
        )
416
        r = await method(self, *args, **kwargs)
1✔
417

418
        transport = r[0]
1✔
419
        sock = transport.get_extra_info("socket")
1✔
420
        if sock:
1✔
421
            ssl_object = transport.get_extra_info("ssl_object")
1✔
422
            if ssl_object:
1✔
423
                socketdata = records.get_socket_data(
1✔
424
                    ssl_object, sock, force_new=True
425
                )  # to link the cnx info to the sslobject
426
                logger().info(
1✔
427
                    f"CREATE_CONNECTION - ssl_object ssl_object={ssl_object} ssl_objectid={id(ssl_object)} socketdata={socketdata}"
428
                )
429
        return r
1✔
430

431
    return hook
1✔
432

433

434
# hook: ssl.SSLObject.write
435
# what: Write buf to the SSL socket and return the number of bytes written.
436
# action: Append the data to an existing SocketRawData. Check if this is an HTTP request.
437
# and record it if this is case, otherwise delete the temporay SocketRawData.
438
def set_hook_for_sslobject_write(records: HTTPRecords, method: Callable):
1✔
439
    def hook(self, buf, *args, **kwargs):
1✔
440
        logger().info(f"WRITE - {type(self)}={id(self)} buf={(b'' + buf)[:20]}")
1✔
441
        socketdata = records.get_socket_data(self, request=True)
1✔
442
        if socketdata:
1✔
443
            logger().info(f"WRITE * - socketdata={socketdata}")
1✔
444

445
        size = method(self, buf, *args, **kwargs)
1✔
446

447
        if socketdata:
1✔
448
            if socketdata.record:
1✔
449
                socketdata.record.send_data(bytes(buf[:size]))
1✔
450
            else:
451
                socketdata.rawdata += bytes(buf[:size])
1✔
452
                http_detected = socketdata.http_detected()
1✔
453
                if http_detected:
1✔
454
                    with httpdbg_initiator(
1✔
455
                        records,
456
                        traceback.extract_stack(),
457
                        method,
458
                        self,
459
                        buf,
460
                        *args,
461
                        **kwargs,
462
                    ) as initiator_and_group:
463
                        initiator, group, is_new = initiator_and_group
1✔
464
                        if is_new:
1✔
465
                            tbegin = socketdata.tbegin - datetime.timedelta(
×
466
                                milliseconds=1
467
                            )
468
                            initiator.tbegin = tbegin
×
469
                            group.tbegin = tbegin
×
470
                        socketdata.record = HTTPRecord(
1✔
471
                            records.current_initiator,
472
                            records.current_group,
473
                            records.current_tag,
474
                            tbegin=socketdata.tbegin,
475
                        )
476
                        socketdata.record.address = socketdata.address
1✔
477
                        socketdata.record.ssl = socketdata.ssl
1✔
478
                        socketdata.record.send_data(socketdata.rawdata)
1✔
479
                        if records.client:
1✔
480
                            records.requests[socketdata.record.id] = socketdata.record
1✔
481
                elif http_detected is False:  # if None, there is nothing to do
×
482
                    records.sockets[id(self)] = None
×
483
        return size
1✔
484

485
    return hook
1✔
486

487

488
# hook: ssl.SSLObject.read
489
# what: Read up to len bytes of data from the SSL socket and return the result as a bytes instance.
490
# action: Append the data to an existing SocketRawData.
491
def set_hook_for_sslobject_read(records: HTTPRecords, method: Callable):
1✔
492
    def hook(self, *args, **kwargs):
1✔
493
        logger().info(f"READ - {type(self)}={id(self)}")
1✔
494
        socketdata = records.get_socket_data(self)
1✔
495
        if socketdata:
1✔
496
            logger().info(f"READ * - socketdata={socketdata}")
1✔
497

498
        r = method(self, *args, **kwargs)
1✔
499

500
        if socketdata and socketdata.record:
1✔
501
            allargs = getcallargs(method, self, *args, **kwargs)
1✔
502
            if allargs.get("buffer"):
1✔
503
                socketdata.record.receive_data(bytes(allargs.get("buffer"))[:r])
×
504
            else:
505
                socketdata.record.receive_data(bytes(r)[: allargs.get("len")])
1✔
506

507
        return r
1✔
508

509
    return hook
1✔
510

511

512
@contextmanager
1✔
513
def hook_socket(records: HTTPRecords) -> Generator[None, None, None]:
1✔
514
    socket.socket.__init__ = decorate(
1✔
515
        records, socket.socket.__init__, set_hook_for_socket_init
516
    )
517

518
    socket.socket.connect = decorate(
1✔
519
        records, socket.socket.connect, set_hook_for_socket_connect
520
    )
521
    socket.socket.recv_into = decorate(
1✔
522
        records, socket.socket.recv_into, set_hook_for_socket_recv_into
523
    )
524
    socket.socket.recv = decorate(records, socket.socket.recv, set_hook_for_socket_recv)
1✔
525
    socket.socket.sendall = decorate(
1✔
526
        records, socket.socket.sendall, set_hook_for_socket_sendall
527
    )
528
    socket.socket.send = decorate(records, socket.socket.send, set_hook_for_socket_send)
1✔
529

530
    if (sys.version_info.major == 3) and (sys.version_info.minor < 12):
1✔
531
        ssl.wrap_socket = decorate(  # type: ignore[attr-defined]
1✔
532
            records, ssl.wrap_socket, set_hook_for_ssl_wrap_socket  # type: ignore[attr-defined]
533
        )
534

535
    ssl.SSLContext.wrap_socket = decorate(
1✔
536
        records, ssl.SSLContext.wrap_socket, set_hook_for_sslcontext_wrap_socket
537
    )
538
    ssl.SSLContext.wrap_bio = decorate(
1✔
539
        records, ssl.SSLContext.wrap_bio, set_hook_for_socket_wrap_bio
540
    )
541

542
    ssl.SSLSocket.connect = decorate(
1✔
543
        records, ssl.SSLSocket.connect, set_hook_for_socket_connect
544
    )
545
    ssl.SSLSocket.recv_into = decorate(
1✔
546
        records, ssl.SSLSocket.recv_into, set_hook_for_socket_recv_into
547
    )
548
    ssl.SSLSocket.recv = decorate(records, ssl.SSLSocket.recv, set_hook_for_socket_recv)
1✔
549
    # ssl.SSLSocket.sendall = decorate(
550
    #     records, ssl.SSLSocket.sendall, set_hook_for_socket_sendall
551
    # )
552
    ssl.SSLSocket.send = decorate(records, ssl.SSLSocket.send, set_hook_for_socket_send)
1✔
553

554
    # for aiohttp
555
    ssl.SSLObject.write = decorate(
1✔
556
        records, ssl.SSLObject.write, set_hook_for_sslobject_write
557
    )
558
    ssl.SSLObject.read = decorate(
1✔
559
        records, ssl.SSLObject.read, set_hook_for_sslobject_read
560
    )
561
    asyncio.BaseEventLoop.create_connection = decorate(
1✔
562
        records,
563
        asyncio.BaseEventLoop.create_connection,
564
        set_hook_for_asyncio_create_connection,
565
    )
566

567
    # only for async HTTP requests (not HTTPS) on Windows
568
    if platform.system().lower() == "windows":
1✔
569
        asyncio.proactor_events._ProactorReadPipeTransport._data_received = decorate(  # type: ignore
×
570
            records,
571
            asyncio.proactor_events._ProactorReadPipeTransport._data_received,  # type: ignore
572
            set_hook_for_socket_recv_into,
573
        )
574
        asyncio.proactor_events._ProactorBaseWritePipeTransport.write = decorate(
×
575
            records,
576
            asyncio.proactor_events._ProactorBaseWritePipeTransport.write,
577
            set_hook_for_socket_send,
578
        )
579

580
    yield
1✔
581

582
    socket.socket.__init__ = undecorate(socket.socket.__init__)
1✔
583

584
    socket.socket.connect = undecorate(socket.socket.connect)
1✔
585
    socket.socket.recv_into = undecorate(socket.socket.recv_into)
1✔
586
    socket.socket.recv = undecorate(socket.socket.recv)
1✔
587
    socket.socket.sendall = undecorate(socket.socket.sendall)
1✔
588
    socket.socket.send = undecorate(socket.socket.send)
1✔
589

590
    if (sys.version_info.major == 3) and (sys.version_info.minor < 12):
1✔
591
        ssl.wrap_socket = undecorate(ssl.wrap_socket)  # type: ignore[attr-defined]
1✔
592

593
    ssl.SSLContext.wrap_socket = undecorate(ssl.SSLContext.wrap_socket)
1✔
594
    ssl.SSLContext.wrap_bio = undecorate(ssl.SSLContext.wrap_bio)
1✔
595

596
    ssl.SSLSocket.connect = undecorate(ssl.SSLSocket.connect)
1✔
597
    ssl.SSLSocket.recv_into = undecorate(ssl.SSLSocket.recv_into)
1✔
598
    ssl.SSLSocket.recv = undecorate(ssl.SSLSocket.recv)
1✔
599
    # ssl.SSLSocket.sendall = undecorate(ssl.SSLSocket.sendall)
600
    ssl.SSLSocket.send = undecorate(ssl.SSLSocket.send)
1✔
601

602
    # for aiohttp / async httpx
603
    ssl.SSLObject.write = undecorate(ssl.SSLObject.write)
1✔
604
    ssl.SSLObject.read = undecorate(ssl.SSLObject.read)
1✔
605
    asyncio.BaseEventLoop.create_connection = undecorate(
1✔
606
        asyncio.BaseEventLoop.create_connection
607
    )
608

609
    # only for async HTTP requests (not HTTPS) on Windows
610
    if platform.system().lower() == "windows":
1✔
611
        asyncio.proactor_events._ProactorReadPipeTransport._data_received = undecorate(  # type: ignore
×
612
            asyncio.proactor_events._ProactorReadPipeTransport._data_received  # type: ignore
613
        )
614
        asyncio.proactor_events._ProactorBaseWritePipeTransport.write = undecorate(
×
615
            asyncio.proactor_events._ProactorBaseWritePipeTransport.write
616
        )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc