···11-(** Connection pool configuration *)
22-33-type config = {
44- max_connections_per_host : int; (** Maximum connections per host *)
55- max_idle_time : float; (** Maximum idle time in seconds *)
66- max_lifetime : float option; (** Maximum connection lifetime *)
77-}
88-99-val default_config : config
1010-(** Default configuration: 10 connections per host, 300s idle time *)
-1
stack/requests/lib/requests.ml
···66module Headers = Headers
77module Auth = Auth
88module Timeout = Timeout
99-module Pool = Pool
109module Body = Body
1110module Response = Response
1211module Client = Client
-1
stack/requests/lib/requests.mli
···88module Headers = Headers
99module Auth = Auth
1010module Timeout = Timeout
1111-module Pool = Pool
1211module Body = Body
1312module Response = Response
1413module Client = Client
+7-19
stack/requests/lib/response.ml
···1414 Log.debug (fun m -> m "Creating response: status=%d url=%s elapsed=%.3fs" status url elapsed);
1515 { status; headers; body; url; elapsed; closed = false }
16161717-let status t = t.status
1818-1919-let ok t = t.status >= 200 && t.status < 300
2020-2121-let is_success t = ok t
2222-2323-let is_redirect t = t.status >= 300 && t.status < 400
1717+let status t = Status.of_int t.status
24182525-let is_client_error t = t.status >= 400 && t.status < 500
1919+let status_code t = t.status
26202727-let is_server_error t = t.status >= 500 && t.status < 600
2121+let ok t = Status.is_success (Status.of_int t.status)
28222923let headers t = t.headers
3024···7064(* Pretty printers *)
7165let pp ppf t =
7266 Format.fprintf ppf "@[<v>Response:@,\
7373- status: %d@,\
6767+ status: %a@,\
7468 url: %s@,\
7569 elapsed: %.3fs@,\
7670 headers: @[%a@]@]"
7777- t.status t.url t.elapsed
7171+ Status.pp (Status.of_int t.status) t.url t.elapsed
7872 Headers.pp_brief t.headers
79738074let pp_detailed ppf t =
8181- let status_desc =
8282- if is_success t then "success"
8383- else if is_redirect t then "redirect"
8484- else if is_client_error t then "client error"
8585- else if is_server_error t then "server error"
8686- else "unknown" in
8775 Format.fprintf ppf "@[<v>Response:@,\
8888- status: %d (%s)@,\
7676+ status: %a@,\
8977 url: %s@,\
9078 elapsed: %.3fs@,\
9179 @[%a@]@]"
9292- t.status status_desc t.url t.elapsed
8080+ Status.pp_hum (Status.of_int t.status) t.url t.elapsed
9381 Headers.pp t.headers
+6-15
stack/requests/lib/response.mli
···7788(** Status *)
991010-val status : t -> int
1111-(** Get HTTP status code *)
1010+val status : t -> Status.t
1111+(** Get HTTP status as Status.t *)
1212+1313+val status_code : t -> int
1414+(** Get HTTP status code as integer *)
12151316val ok : t -> bool
1414-(** Returns true if status is 200-299 *)
1515-1616-val is_success : t -> bool
1717-(** Returns true if status is 200-299 *)
1818-1919-val is_redirect : t -> bool
2020-(** Returns true if status is 300-399 *)
2121-2222-val is_client_error : t -> bool
2323-(** Returns true if status is 400-499 *)
2424-2525-val is_server_error : t -> bool
2626-(** Returns true if status is 500-599 *)
1717+(** Returns true if status is 200-299 (alias for Status.is_success) *)
27182819(** Headers *)
2920
+47-50
stack/requests/lib/session.ml
···286286 Eio.Path.with_open_out ~create:(`Or_truncate 0o644) path @@ fun sink ->
287287 download t ?headers ?auth ?timeout url ~sink
288288289289-(** {1 Batch Operations} *)
290290-291291-let concurrent_requests (type a b) (t : (a, b) t) ?(max_concurrent = 10) tasks =
292292- let sem = Eio.Semaphore.make max_concurrent in
293293-294294- tasks |> Eio.Fiber.List.map ~max_fibers:max_concurrent (fun task ->
295295- Eio.Semaphore.acquire sem;
296296- try
297297- let result = task t in
298298- Eio.Semaphore.release sem;
299299- result
300300- with exn ->
301301- Eio.Semaphore.release sem;
302302- raise exn
303303- )
304304-305305-let map_concurrent (type a b) (t : (a, b) t) ?max_concurrent ~f items =
306306- let tasks = List.map (fun item session -> f session item) items in
307307- concurrent_requests t ?max_concurrent tasks
308289309290let pp ppf t =
310291 Mutex.lock t.mutex;
···392373393374 session
394375395395- (* Individual terms *)
376376+ (* Individual terms - parameterized by app_name *)
396377397397- let persist_cookies_term =
378378+ let persist_cookies_term app_name =
398379 let doc = "Persist cookies to disk between sessions" in
399399- let env = Cmd.Env.info "REQUESTS_PERSIST_COOKIES" in
380380+ let env_name = String.uppercase_ascii app_name ^ "_PERSIST_COOKIES" in
381381+ let env = Cmd.Env.info env_name in
400382 Arg.(value & flag & info ["persist-cookies"] ~env ~doc)
401383402402- let verify_tls_term =
384384+ let verify_tls_term app_name =
403385 let doc = "Skip TLS certificate verification (insecure)" in
404404- let env = Cmd.Env.info "REQUESTS_NO_VERIFY_TLS" in
386386+ let env_name = String.uppercase_ascii app_name ^ "_NO_VERIFY_TLS" in
387387+ let env = Cmd.Env.info env_name in
405388 Term.(const (fun no_verify -> not no_verify) $
406389 Arg.(value & flag & info ["no-verify-tls"] ~env ~doc))
407390408408- let timeout_term =
391391+ let timeout_term app_name =
409392 let doc = "Request timeout in seconds" in
410410- let env = Cmd.Env.info "REQUESTS_TIMEOUT" in
393393+ let env_name = String.uppercase_ascii app_name ^ "_TIMEOUT" in
394394+ let env = Cmd.Env.info env_name in
411395 Arg.(value & opt (some float) None & info ["timeout"] ~env ~docv:"SECONDS" ~doc)
412396413413- let retries_term =
397397+ let retries_term app_name =
414398 let doc = "Maximum number of request retries" in
415415- let env = Cmd.Env.info "REQUESTS_MAX_RETRIES" in
399399+ let env_name = String.uppercase_ascii app_name ^ "_MAX_RETRIES" in
400400+ let env = Cmd.Env.info env_name in
416401 Arg.(value & opt int 3 & info ["max-retries"] ~env ~docv:"N" ~doc)
417402418418- let retry_backoff_term =
403403+ let retry_backoff_term app_name =
419404 let doc = "Retry backoff factor for exponential delay" in
420420- let env = Cmd.Env.info "REQUESTS_RETRY_BACKOFF" in
405405+ let env_name = String.uppercase_ascii app_name ^ "_RETRY_BACKOFF" in
406406+ let env = Cmd.Env.info env_name in
421407 Arg.(value & opt float 0.3 & info ["retry-backoff"] ~env ~docv:"FACTOR" ~doc)
422408423423- let follow_redirects_term =
409409+ let follow_redirects_term app_name =
424410 let doc = "Don't follow HTTP redirects" in
425425- let env = Cmd.Env.info "REQUESTS_NO_FOLLOW_REDIRECTS" in
411411+ let env_name = String.uppercase_ascii app_name ^ "_NO_FOLLOW_REDIRECTS" in
412412+ let env = Cmd.Env.info env_name in
426413 Term.(const (fun no_follow -> not no_follow) $
427414 Arg.(value & flag & info ["no-follow-redirects"] ~env ~doc))
428415429429- let max_redirects_term =
416416+ let max_redirects_term app_name =
430417 let doc = "Maximum number of redirects to follow" in
431431- let env = Cmd.Env.info "REQUESTS_MAX_REDIRECTS" in
418418+ let env_name = String.uppercase_ascii app_name ^ "_MAX_REDIRECTS" in
419419+ let env = Cmd.Env.info env_name in
432420 Arg.(value & opt int 10 & info ["max-redirects"] ~env ~docv:"N" ~doc)
433421434434- let user_agent_term =
422422+ let user_agent_term app_name =
435423 let doc = "User-Agent header to send with requests" in
436436- let env = Cmd.Env.info "REQUESTS_USER_AGENT" in
424424+ let env_name = String.uppercase_ascii app_name ^ "_USER_AGENT" in
425425+ let env = Cmd.Env.info env_name in
437426 Arg.(value & opt (some string) None & info ["user-agent"] ~env ~docv:"STRING" ~doc)
438427439428 (* Combined terms *)
···447436 follow_redirects = follow; max_redirects = max_redir;
448437 user_agent = ua })
449438 $ xdg_term
450450- $ persist_cookies_term
451451- $ verify_tls_term
452452- $ timeout_term
453453- $ retries_term
454454- $ retry_backoff_term
455455- $ follow_redirects_term
456456- $ max_redirects_term
457457- $ user_agent_term)
439439+ $ persist_cookies_term app_name
440440+ $ verify_tls_term app_name
441441+ $ timeout_term app_name
442442+ $ retries_term app_name
443443+ $ retry_backoff_term app_name
444444+ $ follow_redirects_term app_name
445445+ $ max_redirects_term app_name
446446+ $ user_agent_term app_name)
458447459448 let session_term app_name env sw =
460449 let config_t = config_term app_name env#fs in
···465454 ~config:false ~data:true ~cache:true ~state:false ~runtime:false () in
466455 Term.(const (fun (xdg, _xdg_cmd) persist -> (xdg, persist))
467456 $ xdg_term
468468- $ persist_cookies_term)
457457+ $ persist_cookies_term app_name)
469458470459 let env_docs app_name =
471460 let app_upper = String.uppercase_ascii app_name in
···484473 : Base directory for user data files (default: ~/.local/share)\n\n\
485474 **XDG_CACHE_HOME**\n\
486475 : Base directory for user cache files (default: ~/.cache)\n\n\
487487- **REQUESTS_PERSIST_COOKIES**\n\
476476+ **%s_PERSIST_COOKIES**\n\
488477 : Set to '1' to persist cookies by default\n\n\
489489- **REQUESTS_NO_VERIFY_TLS**\n\
478478+ **%s_NO_VERIFY_TLS**\n\
490479 : Set to '1' to disable TLS verification (insecure)\n\n\
491491- **REQUESTS_TIMEOUT**\n\
480480+ **%s_TIMEOUT**\n\
492481 : Default request timeout in seconds\n\n\
493493- **REQUESTS_MAX_RETRIES**\n\
482482+ **%s_MAX_RETRIES**\n\
494483 : Maximum number of retries for failed requests\n\n\
495495- **REQUESTS_USER_AGENT**\n\
484484+ **%s_MAX_REDIRECTS**\n\
485485+ : Maximum number of redirects to follow\n\n\
486486+ **%s_NO_FOLLOW_REDIRECTS**\n\
487487+ : Set to '1' to disable following redirects\n\n\
488488+ **%s_RETRY_BACKOFF**\n\
489489+ : Backoff factor for retry delays\n\n\
490490+ **%s_USER_AGENT**\n\
496491 : Default User-Agent header\n\n\
497492 **HTTP_PROXY**, **HTTPS_PROXY**, **NO_PROXY**\n\
498493 : Proxy configuration (when proxy support is implemented)"
499494 app_name app_upper app_upper app_upper
495495+ app_upper app_upper app_upper app_upper
496496+ app_upper app_upper app_upper app_upper
500497501498 let pp_config ppf config =
502499 let _xdg, xdg_cmd = config.xdg in
+16-46
stack/requests/lib/session.mli
···245245 unit
246246(** Download directly to a file *)
247247248248-(** {1 Batch Operations} *)
249249-250250-val concurrent_requests :
251251- ('clock, 'net) t ->
252252- ?max_concurrent:int ->
253253- (('clock, 'net) t -> 'a) list ->
254254- 'a list
255255-(** Execute multiple requests concurrently with the same session.
256256- Cookies and state are shared safely across all requests.
257257- @param max_concurrent Maximum number of concurrent requests (default: 10) *)
258258-259259-val map_concurrent :
260260- ('clock, 'net) t ->
261261- ?max_concurrent:int ->
262262- f:(('clock, 'net) t -> 'a -> 'b) ->
263263- 'a list ->
264264- 'b list
265265-(** Map a function over a list concurrently using the session *)
266266-267248val pp : Format.formatter -> ('clock, 'net) t -> unit
268249(** Pretty print session configuration *)
269250···322303 ]}
323304*)
324305325325-(** {2 Concurrent Downloads}
326326- {[
327327- let download_all session urls =
328328- Session.map_concurrent session ~max_concurrent:5
329329- ~f:(fun sess url ->
330330- let resp = Session.get sess url in
331331- Response.body resp |> Buf_read.take_all)
332332- urls
333333- ]}
334334-*)
335335-336306(** {1 Cmdliner Integration} *)
337307338308module Cmd : sig
···363333364334 (** {2 Individual Terms} *)
365335366366- val persist_cookies_term : bool Cmdliner.Term.t
367367- (** Term for [--persist-cookies] flag *)
336336+ val persist_cookies_term : string -> bool Cmdliner.Term.t
337337+ (** Term for [--persist-cookies] flag with app-specific env var *)
368338369369- val verify_tls_term : bool Cmdliner.Term.t
370370- (** Term for [--no-verify-tls] flag *)
339339+ val verify_tls_term : string -> bool Cmdliner.Term.t
340340+ (** Term for [--no-verify-tls] flag with app-specific env var *)
371341372372- val timeout_term : float option Cmdliner.Term.t
373373- (** Term for [--timeout SECONDS] option *)
342342+ val timeout_term : string -> float option Cmdliner.Term.t
343343+ (** Term for [--timeout SECONDS] option with app-specific env var *)
374344375375- val retries_term : int Cmdliner.Term.t
376376- (** Term for [--max-retries N] option *)
345345+ val retries_term : string -> int Cmdliner.Term.t
346346+ (** Term for [--max-retries N] option with app-specific env var *)
377347378378- val retry_backoff_term : float Cmdliner.Term.t
379379- (** Term for [--retry-backoff FACTOR] option *)
348348+ val retry_backoff_term : string -> float Cmdliner.Term.t
349349+ (** Term for [--retry-backoff FACTOR] option with app-specific env var *)
380350381381- val follow_redirects_term : bool Cmdliner.Term.t
382382- (** Term for [--no-follow-redirects] flag *)
351351+ val follow_redirects_term : string -> bool Cmdliner.Term.t
352352+ (** Term for [--no-follow-redirects] flag with app-specific env var *)
383353384384- val max_redirects_term : int Cmdliner.Term.t
385385- (** Term for [--max-redirects N] option *)
354354+ val max_redirects_term : string -> int Cmdliner.Term.t
355355+ (** Term for [--max-redirects N] option with app-specific env var *)
386356387387- val user_agent_term : string option Cmdliner.Term.t
388388- (** Term for [--user-agent STRING] option *)
357357+ val user_agent_term : string -> string option Cmdliner.Term.t
358358+ (** Term for [--user-agent STRING] option with app-specific env var *)
389359390360 (** {2 Combined Terms} *)
391361
+1-6
stack/requests/lib/stream.ml
···23232424(* Main request implementation *)
2525let request ~sw ?client ?headers ?body ?auth ?timeout ?follow_redirects
2626- ?max_redirects ?pool_config ~method_ url =
2626+ ?max_redirects ~method_ url =
2727 let client = get_client client in
2828 let start_time = Unix.gettimeofday () in
29293030 Log.info (fun m -> m "Making %s request to %s" (Method.to_string method_) url);
3131-3232- (* Note: pool_config is accepted for API compatibility but not used yet
3333- as Cohttp_eio doesn't expose connection pooling configuration.
3434- This will be implemented when connection pooling is added. *)
3535- let _ = pool_config in
36313732 (* Prepare headers *)
3833 let headers = match headers with