• Stars
    star
    377
  • Rank 113,535 (Top 3 %)
  • Language
    Common Lisp
  • Created over 9 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A fast HTTP client for Common Lisp

Dexador

Build Status Coverage Status

Dexador is yet another HTTP client for Common Lisp with neat APIs and connection-pooling.

Warning

This software is still BETA quality. The APIs will be likely to change.

Differences from Drakma

  • Fast, particularly when requesting to the same host (See Benchmark)
  • Neat APIs
  • Signal a condition when HTTP request failed
  • OpenSSL isn't required for Windows

See also a presentation given at Lisp Meetup #31.

Usage

(dex:get "http://lisp.org/")

(dex:post "https://example.com/login"
          :content '(("name" . "fukamachi") ("password" . "1ispa1ien")))

Posting a form-data

You can specify a form-data at :content in an association list. The data will be sent in application/x-www-form-urlencoded format.

(dex:post "http://example.com/entry/create"
          :content '(("title" . "The Truth About Lisp")
                     ("body" . "In which the truth about lisp is revealed, and some alternatives are enumerated.")))

Auto-detects Multipart

If the association list contains a pathname, the data will be sent as multipart/form-data.

(dex:post "http://example.com/entry/create"
          :content '(("photo" . #P"images/2015030201.jpg")))

Following redirects (GET or HEAD)

If the server reports that the requested page has moved to a different location (indicated with a Location header and a 3XX response code), Dexador will redo the request on the new place, the fourth return value shows.

(dex:head "http://lisp.org")
;=> ""
;   200
;   #<HASH-TABLE :TEST EQUAL :COUNT 7 {100D2A47A3}>
;   #<QURI.URI.HTTP:URI-HTTP http://lisp.org/index.html>
;   NIL

You can limit the count of redirection by specifying :max-redirects with an integer. The default value is 5.

Using cookies

Dexador adopts cl-cookie for its cookie management. All functions takes a cookie-jar instance at :cookie-jar.

(defvar *cookie-jar* (cl-cookie:make-cookie-jar))

(dex:head "https://mixi.jp" :cookie-jar *cookie-jar* :verbose t)
;-> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;   HEAD / HTTP/1.1
;   User-Agent: Dexador/0.1 (SBCL 1.2.9); Darwin; 14.1.0
;   Host: mixi.jp
;   Accept: */*
;   
;   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;   HTTP/1.1 200 OK
;   Date: Tue, 10 Mar 2015 10:16:29 GMT
;   Server: Apache
;   X-Dealer: 152151
;   X-XRDS-Location: https://mixi.jp/xrds.pl
;   Cache-Control: no-cache
;   Pragma: no-cache
;   Vary: User-Agent
;   Content-Type: text/html; charset=EUC-JP
;   Set-Cookie: _auid=9d47ca5a00ce4980c41511beb2626fd4; domain=.mixi.jp; path=/; expires=Thu, 09-Mar-2017 10:16:29 GMT
;   Set-Cookie: _lcp=8ee4121c9866435007fff2c90dc31a4d; domain=.mixi.jp; expires=Wed, 11-Mar-2015 10:16:29 GMT
;   X-Content-Type-Options: nosniff
;   
;   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

;; Again
(dex:head "https://mixi.jp" :cookie-jar *cookie-jar* :verbose t)
;-> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;   HEAD / HTTP/1.1
;   User-Agent: Dexador/0.1 (SBCL 1.2.9); Darwin; 14.1.0
;   Host: mixi.jp
;   Accept: */*
;   Cookie: _auid=b878756ed71a0ed5bcf527e324c78f8c; _lcp=8ee4121c9866435007fff2c90dc31a4d
;   
;   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;   HTTP/1.1 200 OK
;   Date: Tue, 10 Mar 2015 10:16:59 GMT
;   Server: Apache
;   X-Dealer: 152146
;   X-XRDS-Location: https://mixi.jp/xrds.pl
;   Cache-Control: no-cache
;   Pragma: no-cache
;   Vary: User-Agent
;   Content-Type: text/html; charset=EUC-JP
;   Set-Cookie: _auid=b878756ed71a0ed5bcf527e324c78f8c; domain=.mixi.jp; path=/; expires=Thu, 09-Mar-2017 10:16:59 GMT
;   Set-Cookie: _lcp=8ee4121c9866435007fff2c90dc31a4d; domain=.mixi.jp; expires=Wed, 11-Mar-2015 10:16:59 GMT
;   X-Content-Type-Options: nosniff
;   
;   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Basic Authorization

(dex:head "http://www.hatena.ne.jp/" :basic-auth '("nitro_idiot" . "password") :verbose t)
;-> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;   HEAD / HTTP/1.1
;   User-Agent: Dexador/0.1 (SBCL 1.2.9); Darwin; 14.1.0
;   Host: www.hatena.ne.jp
;   Accept: */*
;   Authorization: Basic bml0cm9faWRpb3Q6cGFzc3dvcmQ=
;   
;   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Faking a User-Agent header

You can overwrite the default User-Agent header by simply specifying "User-Agent" in :headers.

(dex:head "http://www.sbcl.org/" :verbose t)
;-> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;   HEAD / HTTP/1.1
;   User-Agent: Dexador/0.1 (SBCL 1.2.6); Darwin; 14.1.0
;   Host: www.sbcl.org
;   Accept: */*
;   
;   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

(dex:head "http://www.sbcl.org/"
          :headers '(("User-Agent" . "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/600.3.18 (KHTML, like Gecko) Version/8.0.3 Safari/600.3.18"))
          :verbose t)
;-> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;   HEAD / HTTP/1.1
;   User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/600.3.18 (KHTML, like Gecko) Version/8.0.3 Safari/600.3.18
;   Host: www.sbcl.org
;   Accept: */*
;   
;   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Reusing a connection

Dexador reuses a connection by default. As it skips a TCP handshake, it would be much faster when you send requests to the same host continuously.

Handling unexpected HTTP status code

Dexador signals a condition http-request-failed when the server returned 4xx or 5xx status code.

;; Handles 400 bad request
(handler-case (dex:get "http://lisp.org")
  (dex:http-request-bad-request ()
    ;; Runs when 400 bad request returned
    )
  (dex:http-request-failed (e)
    ;; For other 4xx or 5xx
    (format *error-output* "The server returned ~D" (dex:response-status e))))

;; Ignore 404 Not Found and continue
(handler-bind ((dex:http-request-not-found #'dex:ignore-and-continue))
  (dex:get "http://lisp.org"))

;; Retry
(handler-bind ((dex:http-request-failed #'dex:retry-request))
  (dex:get "http://lisp.org"))

;; Retry 5 times
(let ((retry-request (dex:retry-request 5 :interval 3)))
  (handler-bind ((dex:http-request-failed retry-request))
    (dex:get "http://lisp.org")))

Proxy

You can connect via proxy.

(dex:get "http://lisp.org/" :proxy "http://proxy.yourcompany.com:8080/")

You can connect via SOCKS5 proxy.

(dex:get "https://www.facebookcorewwwi.onion/" :proxy "socks5://127.0.0.1:9150")

You can set the default proxy by setting dex:*default-proxy* which defaults to the value of the environment variable HTTPS_PROXY or HTTP_PROXY

Functions

All functions take similar arguments.

  • uri (string or quri:uri)
  • method (keyword)
    • The HTTP request method: :GET, :HEAD, :OPTIONS, :PUT, :POST, or :DELETE. The default is :GET.
  • version (number)
    • The version of the HTTP protocol: typically 1.0 or 1.1. The default is 1.1.
  • content (string, alist or pathname)
    • The body of the request.
  • headers (alist)
    • The headers of the request. If the value of a pair is NIL, the header won't be sent. You can overwrite the default headers (Host, User-Agent and Accept) by this with the same header name.
  • basic-auth (cons of username and password)
    • Username and password for basic authorization. This is a cons having username at car and password at cdr. (e.g. '("foo" . "bar"))
  • cookie-jar (cookie-jar of cl-cookie)
    • A cookie jar object.
  • connect-timeout (fixnum)
    • The seconds to timeout until the HTTP connection established. The default is 10, the value of *default-connect-timeout*.
  • read-timeout (fixnum)
    • The seconds to timeout until the whole HTTP body read. The default is 10, the value of *default-read-timeout*.
  • keep-alive (boolean)
    • A flag if the connection keep connected even after the HTTP request. The default is T.
  • use-connection-pool (boolean)
    • When combined with :keep-alive t, will internally cache the socket connection to web servers to avoid having to open new ones. This is compatible with :want-stream t (when you close the returned stream or it is garbage collected the connection will be returned to the pool). If you pass in a stream with :stream then the connection pool is not used (unless there is a redirect to a new web server). This is not supported when using the WINHTTP backend. The default is T.
  • max-redirects (fixnum)
    • The limit of redirections. The default is 5. If the redirection exceeds the limit, functions return the last response (not raise a condition).
  • ssl-key-file, ssl-cert-file, ssl-key-password
    • for HTTPS connection
  • stream
    • The stream to write an HTTP request. This is a way to reuse a connection and commonly used with :keep-alive T. This allows the caller to do connection pooling, etc. It is easier to just use :use-connection-pool t, which is the default, and let the dexador internals take care of this for you (only supported for usocket backends).
  • verbose (boolean)
    • This option is for debugging. When T, it dumps the HTTP request headers.
  • force-binary (boolean)
    • A flag for suppressing auto-decoding of the response body.
  • want-stream (boolean)
    • A flag to get the response body as a stream.
  • proxy (string)
    • for use proxy. defaults to the value of dex:*default-proxy* which defaults to the value of environment variables HTTPS_PROXY or HTTP_PROXY. Not supported on windows currently
  • insecure (boolean)
    • To bypass SSL certificate verification (use at your own risk). The default is NIL, the value of *not-verify-ssl*.

[Function] request

(dex:request uri &key (method get) (version 1.1) content headers
             basic-auth cookie-jar (connect-timeout *default-connect-timeout*)
             (read-timeout *default-read-timeout*) (keep-alive t) (use-connection-pool t)
             (max-redirects 5) ssl-key-file ssl-cert-file ssl-key-password stream
             (verbose *verbose*) force-binary force-string want-stream proxy
             (insecure *not-verify-ssl*) ca-path)
;=> body
;   status
;   response-headers
;   uri
;   stream

Send an HTTP request to uri.

The body is an octet vector or a string if the Content-Type is text/*. If you always want it to return an octet vector, specify :force-binary as T.

The status is an integer which represents HTTP status code.

The response-headers is a hash table which represents HTTP response headers. Note that all hash keys are downcased like "content-type". If there's duplicate HTTP headers, those values are concatenated with a comma.

The uri is a QURI object which represents the last URI Dexador requested.

The stream is a usocket stream to communicate with the HTTP server if the connection is still alive and can be reused. This value may be NIL if :keep-alive is NIL or the server closed the connection with Connection: close header or you are using :use-connection-pool t which handles re-using the connections for you.

This function signals http-request-failed when the HTTP status code is 4xx or 5xx.

[Function] get

(dex:get uri &key version headers basic-auth cookie-jar keep-alive
         use-connection-pool connect-timeout read-timeout max-redirects
         force-binary force-string want-stream ssl-key-file
         ssl-cert-file ssl-key-password stream verbose proxy insecure
         ca-path)

[Function] post

(dex:post uri &key version content headers basic-auth cookie-jar
          keep-alive use-connection-pool connect-timeout read-timeout
          force-binary force-string want-stream ssl-key-file
          ssl-cert-file ssl-key-password stream verbose proxy insecure
          ca-path)

[Function] head

(dex:head uri &key version headers basic-auth cookie-jar connect-timeout
          read-timeout max-redirects ssl-key-file ssl-cert-file
          ssl-key-password stream verbose proxy insecure ca-path)

[Function] put

(dex:put uri &key version content headers basic-auth cookie-jar
         keep-alive use-connection-pool connect-timeout read-timeout
         force-binary force-string want-stream ssl-key-file
         ssl-cert-file ssl-key-password stream verbose proxy insecure
         ca-path)

[Function] patch

(dex:patch uri &key version content headers basic-auth cookie-jar
           keep-alive use-connection-pool connect-timeout read-timeout
           force-binary force-string want-stream ssl-key-file
           ssl-cert-file ssl-key-password stream verbose proxy insecure
           ca-path)

[Function] delete

(dex:delete uri &key version headers basic-auth cookie-jar keep-alive
            use-connection-pool connect-timeout read-timeout
            force-binary force-string want-stream ssl-key-file
            ssl-cert-file ssl-key-password stream verbose proxy insecure
            ca-path)

[Function] fetch

Send a GET request to URI and write the response body to the DESTINATION.

(dex:fetch uri destination &key (if-exists error) verbose proxy insecure)

Benchmark

Benchmark graph

  • Server
    • Sakura VPS 1GB
    • nginx 1.2.7, KeepAlive On
  • Client
    • MacBook Pro OS X Yosemite (CPU: 3GHz Intel Core i7, Memory: 8GB)
    • SBCL 1.2.9
  • Downloads an HTML file (181 bytes).

Drakma

(time (dotimes (i 30) (drakma:http-request "http://files.8arrow.org/181B.html")))
Evaluation took:
  1.012 seconds of real time
  0.174742 seconds of total run time (0.148141 user, 0.026601 system)
  17.29% CPU
  1,683 forms interpreted
  500 lambdas converted
  3,027,928,949 processor cycles
  29,416,656 bytes consed

Dexador

(time (dotimes (i 30) (dex:get "http://files.8arrow.org/181B.html")))
Evaluation took:
  0.499 seconds of real time
  0.028057 seconds of total run time (0.019234 user, 0.008823 system)
  5.61% CPU
  56 forms interpreted
  16 lambdas converted
  1,494,851,690 processor cycles
  1,472,992 bytes consed

See Also

Author

Copyright

Copyright (c) 2015 Eitaro Fukamachi ([email protected])

License

Licensed under the MIT License.

More Repositories

1

woo

A fast non-blocking HTTP server on top of libev
Common Lisp
1,285
star
2

clack

Web server abstraction layer for Common Lisp
Common Lisp
1,052
star
3

caveman

Lightweight web application framework for Common Lisp.
Common Lisp
783
star
4

qlot

A project-local library installer for Common Lisp
Common Lisp
464
star
5

sxql

An SQL generator for Common Lisp.
Common Lisp
361
star
6

fast-http

A fast HTTP request/response parser for Common Lisp.
Common Lisp
343
star
7

mito

An ORM for Common Lisp with migrations, relationships and PostgreSQL support
Common Lisp
290
star
8

ningle

Super micro framework for Common Lisp
Common Lisp
254
star
9

cl-project

Generate modern project skeletons
Common Lisp
234
star
10

prove

Yet another unit testing framework for Common Lisp
Common Lisp
217
star
11

cl-dbi

Database independent interface for Common Lisp
Common Lisp
205
star
12

lack

Lack, the core of Clack
Common Lisp
154
star
13

rove

#1=(yet another . #1#) common lisp testing library
Common Lisp
149
star
14

quri

Yet another URI library for Common Lisp
Common Lisp
111
star
15

websocket-driver

WebSocket server/client implementation for Common Lisp
Common Lisp
104
star
16

datafly

A lightweight database library for Common Lisp.
Common Lisp
99
star
17

utopian

A web framework for Common Lisp never finished.
Common Lisp
95
star
18

lsx

Embeddable HTML templating engine for Common Lisp with JSX-like syntax
Common Lisp
79
star
19

shelly

[OBSOLETE] Use Roswell instead.
Common Lisp
63
star
20

envy

Configuration switcher by an environment variable inspired by Config::ENV.
Common Lisp
57
star
21

integral

[OBSOLETE] Use Mito instead.
Common Lisp
54
star
22

psychiq

Background job processing for Common Lisp
Common Lisp
53
star
23

mondo

Simple Common Lisp REPL
Common Lisp
53
star
24

getac

Quick unit testing tool for competitive programming
Common Lisp
46
star
25

dockerfiles

Dockerfiles for Common Lisp programming
Shell
42
star
26

proc-parse

Procedural vector parser
Common Lisp
36
star
27

jose

A JOSE implementation
Common Lisp
32
star
28

supertrace

Superior Common Lisp `trace` functionality for debugging/profiling real world applications.
Common Lisp
31
star
29

redmine-el

See Redmine on Emacs
Emacs Lisp
30
star
30

legion

Simple multithreading worker mechanism.
Common Lisp
30
star
31

cl-coveralls

Common Lisp
29
star
32

.lem

Lem configuration files
Common Lisp
28
star
33

L5

Yet Another Presentation Tool for Lispers
Clojure
28
star
34

docker-cl-example

Example projects to run/develop Common Lisp web application on Docker container
Common Lisp
27
star
35

event-emitter

Event mechanism for Common Lisp objects.
Common Lisp
27
star
36

assoc-utils

Utilities for manipulating association lists.
Common Lisp
26
star
37

clozure-cl

Unofficial mirror of Clozure CL
Common Lisp
25
star
38

myway

Sinatra-compatible URL routing library for Common Lisp
Common Lisp
25
star
39

anypool

General-purpose connection pooling library for Common Lisp
Common Lisp
25
star
40

fast-websocket

Optimized low-level WebSocket protocol parser written in Common Lisp
Common Lisp
24
star
41

uncl

Un-Common Lisp on Common Lisp
Common Lisp
22
star
42

cl-locale

Simple i18n library for Common Lisp
Common Lisp
22
star
43

ragno

Common Lisp Web crawling library based on Psychiq.
Common Lisp
20
star
44

safety-params

Check params
Common Lisp
19
star
45

mito-auth

User authorization for Mito classes.
Common Lisp
18
star
46

cl-cookie

HTTP cookie manager
Common Lisp
18
star
47

http-body

HTTP POST data parser.
Common Lisp
17
star
48

xsubseq

Efficient way to use "subseq"s in Common Lisp
Common Lisp
16
star
49

smart-buffer

Smart octets buffer.
Common Lisp
16
star
50

re21

CL21's spin-off project that provides neat APIs for regular expressions.
Common Lisp
15
star
51

lev

libev bindings for Common Lisp
Common Lisp
15
star
52

.emacs.d

My .emacs.d
Emacs Lisp
15
star
53

lesque

[OBSOLETE] Use Psychiq instead.
Common Lisp
14
star
54

pem

PEM parser.
Common Lisp
14
star
55

circular-streams

Circularly readable streams for Common Lisp.
Common Lisp
14
star
56

mito-attachment

Mito mixin class for file management outside of RDBMS
Common Lisp
14
star
57

webapi

CLOS-based wrapper builder for Web APIs.
Common Lisp
14
star
58

emacs-config

[OBSOLETE] More simplified version is
Emacs Lisp
13
star
59

yapool

A Common Lisp command-line tool for executing shell commands via SSH.
12
star
60

asn1

ASN.1 decoder
Common Lisp
11
star
61

cl-line-bot-sdk

SDK for the LINE Messaging API for Common Lisp
Common Lisp
11
star
62

id3v2

ID3v2 parser
Common Lisp
10
star
63

can

A role-based access right control library.
Common Lisp
10
star
64

kindly-mode

Amazon Kindle-like view mode for Emacs.
Emacs Lisp
10
star
65

wsock

Low-level UNIX socket library
Common Lisp
9
star
66

hatenablog-theme-writer

物書きのためのブログテーマ「Writer」 for はてなブログ
CSS
7
star
67

clee

Common Lisp Event Engine
Common Lisp
6
star
68

fukacl

Fukamachi Common Lisp Package
Common Lisp
6
star
69

ponzu.db

O/R Mapper, a part of Ponzu Framework, for Common Lisp
Common Lisp
6
star
70

gotanda

Common Lisp
6
star
71

neovim-config

~/.config/nvim
Vim Script
6
star
72

trivial-utf-8

Imported from the original darcs repo.
Common Lisp
5
star
73

mp3-duration

Get the duration of an MP3 file
Common Lisp
5
star
74

clbuild

Unofficial fork of clbuild
Shell
5
star
75

asdf-c-test-file

Provides ASDF component :test-file.
Common Lisp
5
star
76

as-interval

An extension of cl-async for introducing 'interval' feature.
Common Lisp
5
star
77

sxql-abstract

An abstraction layer for SQL between RDBMS.
Common Lisp
5
star
78

fukamachi.github.com

HTML
4
star
79

p5-shelly

[DEPRECATED] Moved to https://github.com/fukamachi/shelly
Perl
4
star
80

github-webhook

Docker container to listen for GitHub webhook events
Common Lisp
4
star
81

dont-type-twice-el

Supports your effective text editing.
Emacs Lisp
4
star
82

nail

Common Lisp
4
star
83

lem-vi-sexp

vim-sexp port for Lem
Common Lisp
4
star
84

multival-plist

Property List stores multiple values per one key.
Common Lisp
4
star
85

kunitada-bot

All tweets should be "fastest".
Ruby
3
star
86

closure-library-skeleton

Skeleton files for a project using Google Closure Library.
JavaScript
3
star
87

clack-doc

[DEPRECATED] Documentation tool for Clack (I moved them to Quickdocs.org)
Common Lisp
3
star
88

ac-swift

Swift auto completion for Emacs
Emacs Lisp
3
star
89

gotumda

Put all your tasks into one bucket.
JavaScript
3
star
90

opImKayacComPlugin

PHP
2
star
91

partial-bench

A tiny benchmarking library to get a running time of a specific part.
Common Lisp
2
star
92

p5-gotumda

Communicate over tasks.
JavaScript
2
star
93

Plack-Middleware-Try

Plack Middleware to catch exceptions.
Perl
2
star
94

swank.ros

Common Lisp
2
star
95

Plack-Middleware-StackTraceLog

Plack Middleware for logging when your app dies.
Perl
1
star
96

cl-weather-jp

Get weather in Japan
Common Lisp
1
star
97

rove-test-example

Common Lisp
1
star