jawah / niquests

“Safest, Fastest, Easiest, and Most advanced” Python HTTP Client. Production Ready! Drop-in replacement for Requests. HTTP/1.1, HTTP/2, and HTTP/3 supported. With WebSocket!
https://niquests.readthedocs.io/en/latest/
Apache License 2.0
1.05k stars 23 forks source link

niquests.exceptions.ConnectionError: Stream 1 was reset by remote peer. Reason: 0xd. #150

Closed ghbm-itk closed 1 month ago

ghbm-itk commented 1 month ago

Problem

When using requests to perform my get I get a 401 which is expected. When using niquests I get the following error

niquests.exceptions.ConnectionError: Stream 1 was reset by remote peer. Reason: 0xd.

My requests is version 2.32.3

Reproduction Steps

import niquests
niquests.get("https://api.statstidende.dk/v1/messages")

System Information

$ python -m niquests.help
{
  "charset_normalizer": {
    "version": "3.4.0"
  },
  "http1": {
    "h11": "0.14.0"
  },
  "http2": {
    "jh2": "5.0.3"
  },
  "http3": {
    "enabled": true,
    "qh3": "1.2.0"
  },
  "idna": {
    "version": "3.10"
  },
  "implementation": {
    "name": "CPython",
    "version": "3.12.4"
  },
  "niquests": {
    "version": "3.9.0"
  },
  "ocsp": {
    "enabled": true
  },
  "platform": {
    "release": "10",
    "system": "Windows"
  },
  "system_ssl": {
    "version": "300000d0"
  },
  "urllib3.future": {
    "cohabitation_version": "2.2.3",
    "version": "2.10.902"
  },
  "wassima": {
    "certifi_fallback": false,
    "enabled": true,
    "version": "1.1.3"
  }
}
Ousret commented 1 month ago

This case is somewhat a special edge case. The error here is to be interpreted as follow: "I can do http2, but for that particular resource, I won't do it. Use http1.1 instead" https://www.rfc-editor.org/rfc/rfc9113.html#name-error-codes

Now, I found another issue with your server, even if I disable http2, like so:

from niquests import Session

with Session(disable_http2=True, disable_http3=True) as s:
    resp = s.get("https://api.statstidende.dk/v1/messages")

    print(resp)

The server (Microsoft-IIS/10.0) kills the connection immediately after the request. This is due to an error in the TLS implementation of your remote peer. (the server don't like secure parameters, like disabling renegotiation) and we don't like insecure parameters.

The solution would be to inject a custom SSL context without the OP_NO_RENEGOTIATION flag in options.

I am closing this, as it is not an issue with Niquests.

ghbm-itk commented 1 month ago

The get requests works fine with requests and curl.

I was exited to use niquests due to in memory certificates, but this sadly makes it unusable for me

Ousret commented 1 month ago

I understand, our strict security policy makes this harder.

But you still can!

Just do this

import ssl
setattr(ssl, "OP_NO_RENEGOTIATION", None)  # do this before import Niquests!

from niquests import Session

with Session(disable_http2=True, disable_http3=True) as s:
    resp = s.get("https://api.statstidende.dk/v1/messages")

    print(resp)

And it will go away! We will think of a way to parametrize this.

regards!

ghbm-itk commented 1 month ago

You're right it worked! Thanks :)

But it still proves that niquests isn't a complete drop in for requests

Ousret commented 1 month ago

Update: we've improved our behavior by following curl auto downgrade. see v3.9.1

you no longer need to fully disable http2 and http3.

import ssl
setattr(ssl, "OP_NO_RENEGOTIATION", None)  # still needed for your server with broken tls impl

from niquests import Session

if __name__ == "__main__":
    with Session() as s:
        resp = s.get("https://api.statstidende.dk/v1/messages")

        print(resp)