babashka / http-client

HTTP client for Clojure and Babashka built on java.net.http
MIT License
110 stars 12 forks source link

Request seems to hang or return "Exceptional status code: 502" #57

Open seowalex opened 3 days ago

seowalex commented 3 days ago

I am attempting to make a GET request to Uptime Kuma (to make use of their push-based monitoring using a URL like http://uptime-kuma/api/push/XXXXXXXXXX). The service is proxied through Tailscale (in case it makes a difference). The following requests work:

* processing: http://uptime-kuma/api/push/XXXXXXXXXX
*   Trying 100.65.136.120:80...
* Connected to uptime-kuma (100.65.136.120) port 80
> GET /api/push/XXXXXXXXXX HTTP/1.1
> Host: uptime-kuma
> User-Agent: curl/8.2.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Length: 11
< Content-Type: application/json; charset=utf-8
< Date: Sun, 30 Jun 2024 09:17:32 GMT
< Etag: W/"b-Ai2R8hgEarLmHKwesT1qcY913ys"
< X-Frame-Options: SAMEORIGIN
<
* Connection #0 to host uptime-kuma left intact
{"ok":true}
{:status 200,
 :headers
 {"content-length" "11",
  "content-type" "application/json; charset=utf-8",
  "date" "Sun, 30 Jun 2024 09:20:29 GMT",
  "etag" "W/\"b-Ai2R8hgEarLmHKwesT1qcY913ys\"",
  "x-frame-options" "SAMEORIGIN"},
 :body "{\"ok\":true}",
 :err "",
 :process
 #object[java.lang.ProcessImpl 0x4d52ae94 "Process[pid=32501, exitValue=0]"],
 :exit 0}
{:opts {:method :get, :url "http://uptime-kuma/api/push/XXXXXXXXXX"},
 :body "{\"ok\":true}",
 :headers
 {:content-length "11",
  :content-type "application/json; charset=utf-8",
  :date "Sun, 30 Jun 2024 09:20:29 GMT",
  :etag "W/\"b-Ai2R8hgEarLmHKwesT1qcY913ys\"",
  :x-frame-options "SAMEORIGIN"},
 :status 200}

However, trying to make the same request using babashka.http fails (it either hangs indefinitely or returns "Exceptional status code: 502"):

----- Error --------------------------------------------------------------------
Type:     clojure.lang.ExceptionInfo
Message:  Exceptional status code: 502
Data:     {:status 502, :body "", :version :http1.1, :headers {"content-length" "0", "date" "Sun, 30 Jun 2024 09:11:05 GMT"}, :uri #object[java.net.URI 0xc3e6007 "http://uptime-kuma/api/push/XXXXXXXXXX"], :request {:headers {:accept "*/*", :accept-encoding ["gzip" "deflate"], :user-agent "babashka.http-client/0.4.18"}, :uri #object[java.net.URI 0xc3e6007 "http://uptime-kuma/api/push/XXXXXXXXXX"], :method :get}}
Location: /home/seowalex/.infra/scripts/./rclone.clj:49:8

----- Context ------------------------------------------------------------------
49:   (prn (http/get "http://uptime-kuma/api/push/XXXXXXXXXX"))
           ^--- Exceptional status code: 502
50:   (prn (curl/get "http://uptime-kuma/api/push/XXXXXXXXXX"))
51:   (prn @(http-kit/get "http://uptime-kuma/api/push/XXXXXXXXXX")))

----- Stack trace --------------------------------------------------------------
babashka.http-client.interceptors/fn--28140     - <built-in>
babashka.http-client.internal/then              - <built-in>
babashka.http-client.internal/request/fn--28241 - <built-in>
clojure.core/reduce                             - <built-in>
babashka.http-client.internal/request           - <built-in>
... (run with --debug to see elided elements)
babashka.http-client/get                        - <built-in>
user                                            - /home/seowalex/.infra/scripts/./rclone.clj:49:8
clojure.core/prn                                - <built-in>
user                                            - /home/seowalex/.infra/scripts/./rclone.clj:49:3
user                                            - /home/seowalex/.infra/scripts/./rclone.clj:8:1

Given that it only fails to work with babashka.http-client, it would seem like a bug in the library, but I don't seem to be able to figure out where the problem is. I am happy to provide any more information if needed.

borkdude commented 3 days ago

Try it with vanilla java.net.http as well. If it happens there as well, it's probably not an issue with bb.http-client and vice versa. Also try it with JVM vs bb (not sure if you're using bb).

seowalex commented 2 days ago

I tried using vanilla java.net.http and it seems to error as well:

#!/usr/bin/env bb

(-> java.net.http.HttpClient
    .newHttpClient
    (.send (-> java.net.http.HttpRequest
               (.newBuilder (java.net.URI.
                              "http://uptime-kuma/api/push/XXXXXXXXXX"))
               .build)
           (.ofString java.net.http.HttpResponse$BodyHandlers))
    prn)
#object[jdk.internal.net.http.HttpResponseImpl 0xc7af3f7 "(GET http://uptime-kuma/api/push/XXXXXXXXXX) 502"]

I suppose the next step is to try with Java itself.

seowalex commented 2 days ago

I tried it with Java 21, and it returns the same error, so looks like this is a Java problem.

Edit: Setting some debug flags shows the headers sent, which reveals the true cause:

GET /api/push/XXXXXXXXXX HTTP/1.1
Connection: Upgrade, HTTP2-Settings
Host: uptime-kuma
HTTP2-Settings: AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA
Upgrade: h2c
User-Agent: Java-http-client/21.0.3

Looks like by default it is trying to upgrade to HTTP/2, which Uptime Kuma is apparently not very happy about (causing it to send a 502 Error).

seowalex commented 2 days ago

While this default [mimics Java](https://docs.oracle.com/en/java/javase/21/docs/api/java.net.http/java/net/http/HttpClient.html#version()), it is surprising (at least to me) since curl defaults to HTTP/1.1. Can I suggest adding the default to the docs?

borkdude commented 2 days ago

Yes, PR welcome for doc change. Glad you found the issue.