From 6c3fff90da4a6c9ef3b7f99b046a8baba13fd840 Mon Sep 17 00:00:00 2001
From: chandrusf
Date: Fri, 20 Apr 2007 00:36:29 +0000
Subject: [PATCH] Optimised URL encoding. Removed dependency on inets by
implementing base64 encoding/decoding in ibrowse itself.
---
README | 9 +++-
doc/ibrowse_lib.html | 12 +++++
src/ibrowse_http_client.erl | 5 +-
src/ibrowse_lib.erl | 97 ++++++++++++++++++++++++++++++++++---
vsn.mk | 2 +-
5 files changed, 114 insertions(+), 11 deletions(-)
diff --git a/README b/README
index 6a441c0..3f0b41a 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-$Id: README,v 1.8 2007/03/21 00:26:40 chandrusf Exp $
+$Id: README,v 1.9 2007/04/20 00:36:29 chandrusf Exp $
ibrowse is a HTTP client. The following are a list of features.
- RFC2616 compliant (AFAIK)
@@ -22,6 +22,13 @@ Comments to : Chandrashekhar.Mullaparthi@t-mobile.co.uk
CONTRIBUTIONS & CHANGE HISTORY
==============================
+20-04-2007 - Geoff Cant sent a patch to remove URL encoding for digits in
+ ibrowse_lib:url_encode/1.
+ ibrowse had a dependency on the inets application because the
+ ibrowse_http_client.erl invoked httpd_util:encode_base64/1. This
+ dependency is now removed and the encode_base64/1 has been
+ implemented in ibrowse_lib.erl
+
06-03-2007 - Eric Merritt sent a patch to support WebDAV requests.
12-01-2007 - Derek Upham sent in a bug fix. The reset_state function was not
diff --git a/doc/ibrowse_lib.html b/doc/ibrowse_lib.html
index 81a531f..7a00d4f 100644
--- a/doc/ibrowse_lib.html
+++ b/doc/ibrowse_lib.html
@@ -15,9 +15,11 @@ Module with a few useful functions.
@@ -30,6 +32,11 @@ Module with a few useful functions.
M = integer() -- number of hex digits required
N = integer() -- the number to represent as hex
+
+decode_base64(List::In) -> Out | exit({error, invalid_input})
+
- In = string() | binary()
- Out = string() | binary()
+Implements the base64 decoding algorithm. The output data type matches in the input data type.
+
decode_rfc822_date(String) -> term()
@@ -42,6 +49,11 @@ Module with a few useful functions.
drv_ue(Str, Port) -> term()
+
+encode_base64(List::In) -> Out
+
- In = string() | binary()
- Out = string() | binary()
+Implements the base64 encoding algorithm. The output data type matches in the input data type.
+
status_code(StatusCode::status_code()) -> StatusDescription
diff --git a/src/ibrowse_http_client.erl b/src/ibrowse_http_client.erl
index 4495e61..6ace2fb 100644
--- a/src/ibrowse_http_client.erl
+++ b/src/ibrowse_http_client.erl
@@ -6,7 +6,7 @@
%%% Created : 11 Oct 2003 by Chandrashekhar Mullaparthi
%%%-------------------------------------------------------------------
-module(ibrowse_http_client).
--vsn('$Id: ibrowse_http_client.erl,v 1.10 2007/03/21 00:26:41 chandrusf Exp $ ').
+-vsn('$Id: ibrowse_http_client.erl,v 1.11 2007/04/20 00:36:30 chandrusf Exp $ ').
-behaviour(gen_server).
%%--------------------------------------------------------------------
@@ -571,7 +571,8 @@ cons_headers(Headers) ->
cons_headers([], Acc) ->
encode_headers(Acc);
cons_headers([{basic_auth, {U,P}} | T], Acc) ->
- cons_headers(T, [{"Authorization", ["Basic ", httpd_util:encode_base64(U++":"++P)]} | Acc]);
+ cons_headers(T, [{"Authorization",
+ ["Basic ", ibrowse_lib:encode_base64(U++":"++P)]} | Acc]);
cons_headers([{cookie, Cookie} | T], Acc) ->
cons_headers(T, [{"Cookie", Cookie} | Acc]);
cons_headers([{content_length, L} | T], Acc) ->
diff --git a/src/ibrowse_lib.erl b/src/ibrowse_lib.erl
index 8180b9f..51911c0 100644
--- a/src/ibrowse_lib.erl
+++ b/src/ibrowse_lib.erl
@@ -5,7 +5,7 @@
%% @doc Module with a few useful functions
-module(ibrowse_lib).
--vsn('$Id: ibrowse_lib.erl,v 1.4 2007/03/21 00:26:41 chandrusf Exp $ ').
+-vsn('$Id: ibrowse_lib.erl,v 1.5 2007/04/20 00:36:30 chandrusf Exp $ ').
-author('chandru').
-ifdef(debug).
-compile(export_all).
@@ -16,7 +16,10 @@
status_code/1,
dec2hex/2,
drv_ue/1,
- drv_ue/2]).
+ drv_ue/2,
+ encode_base64/1,
+ decode_base64/1
+ ]).
drv_ue(Str) ->
[{port, Port}| _] = ets:lookup(ibrowse_table, port),
@@ -36,6 +39,8 @@ drv_ue(Str, Port) ->
url_encode(Str) when list(Str) ->
url_encode_char(lists:reverse(Str), []).
+url_encode_char([X | T], Acc) when X >= $0, X =< $9 ->
+ url_encode_char(T, [X | Acc]);
url_encode_char([X | T], Acc) when X >= $a, X =< $z ->
url_encode_char(T, [X | Acc]);
url_encode_char([X | T], Acc) when X >= $A, X =< $Z ->
@@ -93,8 +98,8 @@ month_int("Nov") -> 11;
month_int("Dec") -> 12.
%% @doc Given a status code, returns an atom describing the status code.
-%% @spec status_code(StatusCode) -> StatusDescription
-%% StatusCode = string() | integer()
+%% @spec status_code(StatusCode::status_code()) -> StatusDescription
+%% status_code() = string() | integer()
%% StatusDescription = atom()
status_code(100) -> continue;
status_code(101) -> switching_protocols;
@@ -147,11 +152,89 @@ status_code(X) when is_list(X) -> status_code(list_to_integer(X));
status_code(_) -> unknown_status_code.
%% @doc dec2hex taken from gtk.erl in std dist
-%% @spec dec2hex(M, N) -> string()
-%% M = integer() - number of hex digits required
-%% N = integer() - the number to represent as hex
+%% M = integer() -- number of hex digits required
+%% N = integer() -- the number to represent as hex
+%% @spec dec2hex(M::integer(), N::integer()) -> string()
dec2hex(M,N) -> dec2hex(M,N,[]).
dec2hex(0,_N,Ack) -> Ack;
dec2hex(M,N,Ack) -> dec2hex(M-1,N bsr 4,[d2h(N band 15)|Ack]).
+%% @doc Implements the base64 encoding algorithm. The output data type matches in the input data type.
+%% @spec encode_base64(In) -> Out
+%% In = string() | binary()
+%% Out = string() | binary()
+encode_base64(List) when list(List) ->
+ encode_base64_1(list_to_binary(List));
+encode_base64(Bin) when binary(Bin) ->
+ List = encode_base64_1(Bin),
+ list_to_binary(List).
+
+encode_base64_1(<>) ->
+ [int_to_b64(A), int_to_b64(B),
+ int_to_b64(C), int_to_b64(D) | encode_base64_1(Rest)];
+encode_base64_1(<>) ->
+ [int_to_b64(A), int_to_b64(B), int_to_b64(C bsl 2), $=];
+encode_base64_1(<>) ->
+ [int_to_b64(A), int_to_b64(B bsl 4), $=, $=];
+encode_base64_1(<<>>) ->
+ [].
+
+%% @doc Implements the base64 decoding algorithm. The output data type matches in the input data type.
+%% @spec decode_base64(In) -> Out | exit({error, invalid_input})
+%% In = string() | binary()
+%% Out = string() | binary()
+decode_base64(List) when list(List) ->
+ decode_base64_1(List, []);
+decode_base64(Bin) when binary(Bin) ->
+ List = decode_base64_1(binary_to_list(Bin), []),
+ list_to_binary(List).
+
+decode_base64_1([H | T], Acc) when ((H == $\t) or
+ (H == 32) or
+ (H == $\r) or
+ (H == $\n)) ->
+ decode_base64_1(T, Acc);
+
+decode_base64_1([$=, $=], Acc) ->
+ lists:reverse(Acc);
+decode_base64_1([$=, _ | _], _Acc) ->
+ exit({error, invalid_input});
+
+decode_base64_1([A1, B1, $=, $=], Acc) ->
+ A = b64_to_int(A1),
+ B = b64_to_int(B1),
+ Oct1 = (A bsl 2) bor (B bsr 4),
+ decode_base64_1([], [Oct1 | Acc]);
+decode_base64_1([A1, B1, C1, $=], Acc) ->
+ A = b64_to_int(A1),
+ B = b64_to_int(B1),
+ C = b64_to_int(C1),
+ Oct1 = (A bsl 2) bor (B bsr 4),
+ Oct2 = ((B band 16#f) bsl 6) bor (C bsr 2),
+ decode_base64_1([], [Oct2, Oct1 | Acc]);
+decode_base64_1([A1, B1, C1, D1 | T], Acc) ->
+ A = b64_to_int(A1),
+ B = b64_to_int(B1),
+ C = b64_to_int(C1),
+ D = b64_to_int(D1),
+ Oct1 = (A bsl 2) bor (B bsr 4),
+ Oct2 = ((B band 16#f) bsl 4) bor (C bsr 2),
+ Oct3 = ((C band 2#11) bsl 6) bor D,
+ decode_base64_1(T, [Oct3, Oct2, Oct1 | Acc]);
+decode_base64_1([], Acc) ->
+ lists:reverse(Acc).
+
+%% Taken from httpd_util.erl
+int_to_b64(X) when X >= 0, X =< 25 -> X + $A;
+int_to_b64(X) when X >= 26, X =< 51 -> X - 26 + $a;
+int_to_b64(X) when X >= 52, X =< 61 -> X - 52 + $0;
+int_to_b64(62) -> $+;
+int_to_b64(63) -> $/.
+
+%% Taken from httpd_util.erl
+b64_to_int(X) when X >= $A, X =< $Z -> X - $A;
+b64_to_int(X) when X >= $a, X =< $z -> X - $a + 26;
+b64_to_int(X) when X >= $0, X =< $9 -> X - $0 + 52;
+b64_to_int($+) -> 62;
+b64_to_int($/) -> 63.
diff --git a/vsn.mk b/vsn.mk
index 30fd5d9..e7438d4 100644
--- a/vsn.mk
+++ b/vsn.mk
@@ -1,2 +1,2 @@
-IBROWSE_VSN = 1.2.5
+IBROWSE_VSN = 1.2.6