1%% ``Licensed under the Apache License, Version 2.0 (the "License"); 2%% you may not use this file except in compliance with the License. 3%% You may obtain a copy of the License at 4%% 5%% http://www.apache.org/licenses/LICENSE-2.0 6%% 7%% Unless required by applicable law or agreed to in writing, software 8%% distributed under the License is distributed on an "AS IS" BASIS, 9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10%% See the License for the specific language governing permissions and 11%% limitations under the License. 12%% 13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. 14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings 15%% AB. All Rights Reserved.'' 16%% 17%% $Id: httpd_util.erl,v 1.1 2008/12/17 09:53:34 mikpe Exp $ 18%% 19-module(httpd_util). 20-export([key1search/2, key1search/3, lookup/2, lookup/3, multi_lookup/2, 21 lookup_mime/2, lookup_mime/3, lookup_mime_default/2, 22 lookup_mime_default/3, reason_phrase/1, message/3, rfc1123_date/0, 23 rfc1123_date/1, day/1, month/1, decode_hex/1, decode_base64/1, encode_base64/1, 24 flatlength/1, split_path/1, split_script_path/1, suffix/1, to_upper/1, 25 to_lower/1, split/3, header/2, header/3, header/4, uniq/1, 26 make_name/2,make_name/3,make_name/4,strip/1, 27 hexlist_to_integer/1,integer_to_hexlist/1, 28 convert_request_date/1,create_etag/1,create_etag/2,getSize/1, 29 response_generated/1]). 30 31%%Since hexlist_to_integer is a lousy name make a name convert 32-export([encode_hex/1]). 33-include("httpd.hrl"). 34 35%% key1search 36 37key1search(TupleList,Key) -> 38 key1search(TupleList,Key,undefined). 39 40key1search(TupleList,Key,Undefined) -> 41 case lists:keysearch(Key,1,TupleList) of 42 {value,{Key,Value}} -> 43 Value; 44 false -> 45 Undefined 46 end. 47 48%% lookup 49 50lookup(Table,Key) -> 51 lookup(Table,Key,undefined). 52 53lookup(Table,Key,Undefined) -> 54 case catch ets:lookup(Table,Key) of 55 [{Key,Value}|_] -> 56 Value; 57 _-> 58 Undefined 59 end. 60 61%% multi_lookup 62 63multi_lookup(Table,Key) -> 64 remove_key(ets:lookup(Table,Key)). 65 66remove_key([]) -> 67 []; 68remove_key([{_Key,Value}|Rest]) -> 69 [Value|remove_key(Rest)]. 70 71%% lookup_mime 72 73lookup_mime(ConfigDB,Suffix) -> 74 lookup_mime(ConfigDB,Suffix,undefined). 75 76lookup_mime(ConfigDB,Suffix,Undefined) -> 77 [{mime_types,MimeTypesDB}|_]=ets:lookup(ConfigDB,mime_types), 78 case ets:lookup(MimeTypesDB,Suffix) of 79 [] -> 80 Undefined; 81 [{Suffix,MimeType}|_] -> 82 MimeType 83 end. 84 85%% lookup_mime_default 86 87lookup_mime_default(ConfigDB,Suffix) -> 88 lookup_mime_default(ConfigDB,Suffix,undefined). 89 90lookup_mime_default(ConfigDB,Suffix,Undefined) -> 91 [{mime_types,MimeTypesDB}|_]=ets:lookup(ConfigDB,mime_types), 92 case ets:lookup(MimeTypesDB,Suffix) of 93 [] -> 94 case ets:lookup(ConfigDB,default_type) of 95 [] -> 96 Undefined; 97 [{default_type,DefaultType}|_] -> 98 DefaultType 99 end; 100 [{Suffix,MimeType}|_] -> 101 MimeType 102 end. 103 104%% reason_phrase 105reason_phrase(100) -> "Continue"; 106reason_phrase(101) -> "Swithing protocol"; 107reason_phrase(200) -> "OK"; 108reason_phrase(201) -> "Created"; 109reason_phrase(202) -> "Accepted"; 110reason_phrase(204) -> "No Content"; 111reason_phrase(205) -> "Reset Content"; 112reason_phrase(206) -> "Partial Content"; 113reason_phrase(301) -> "Moved Permanently"; 114reason_phrase(302) -> "Moved Temporarily"; 115reason_phrase(304) -> "Not Modified"; 116reason_phrase(400) -> "Bad Request"; 117reason_phrase(401) -> "Unauthorized"; 118reason_phrase(402) -> "Payment Required"; 119reason_phrase(403) -> "Forbidden"; 120reason_phrase(404) -> "Not Found"; 121reason_phrase(405) -> "Method Not Allowed"; 122reason_phrase(408) -> "Request Timeout"; 123reason_phrase(411) -> "Length Required"; 124reason_phrase(414) -> "Request-URI Too Long"; 125reason_phrase(412) -> "Precondition Failed"; 126reason_phrase(416) -> "request Range Not Satisfiable"; 127reason_phrase(417) -> "Expectation failed"; 128reason_phrase(500) -> "Internal Server Error"; 129reason_phrase(501) -> "Not Implemented"; 130reason_phrase(502) -> "Bad Gateway"; 131reason_phrase(503) -> "Service Unavailable"; 132reason_phrase(_) -> "Internal Server Error". 133 134%% message 135 136message(301,URL,_) -> 137 "The document has moved <A HREF=\""++URL++"\">here</A>."; 138message(304,_URL,_) -> 139 "The document has not been changed."; 140message(400,none,_) -> 141 "Your browser sent a query that this server could not understand."; 142message(401,none,_) -> 143 "This server could not verify that you 144are authorized to access the document you 145requested. Either you supplied the wrong 146credentials (e.g., bad password), or your 147browser does not understand how to supply 148the credentials required."; 149message(403,RequestURI,_) -> 150 "You do not have permission to access "++RequestURI++" on this server."; 151message(404,RequestURI,_) -> 152 "The requested URL "++RequestURI++" was not found on this server."; 153message(412,none,_) -> 154 "The requested preconditions where false"; 155message(414,ReasonPhrase,_) -> 156 "Message "++ReasonPhrase++"."; 157message(416,ReasonPhrase,_) -> 158 ReasonPhrase; 159 160message(500,none,ConfigDB) -> 161 ServerAdmin=lookup(ConfigDB,server_admin,"unknown@unknown"), 162 "The server encountered an internal error or 163misconfiguration and was unable to complete 164your request. 165<P>Please contact the server administrator "++ServerAdmin++", 166and inform them of the time the error occurred 167and anything you might have done that may have 168caused the error."; 169message(501,{Method,RequestURI,HTTPVersion},_ConfigDB) -> 170 Method++" to "++RequestURI++" ("++HTTPVersion++") not supported."; 171message(503,String,_ConfigDB) -> 172 "This service in unavailable due to: "++String. 173 174%%convert_rfc_date(Date)->{{YYYY,MM,DD},{HH,MIN,SEC}} 175 176convert_request_date([D,A,Y,DateType|Rest]) -> 177 Func=case DateType of 178 $\, -> 179 fun convert_rfc1123_date/1; 180 $\ -> 181 fun convert_ascii_date/1; 182 _ -> 183 fun convert_rfc850_date/1 184 end, 185 case catch Func([D,A,Y,DateType|Rest])of 186 {ok,Date} -> 187 Date; 188 _Error -> 189 bad_date 190 end. 191 192convert_rfc850_date(DateStr) -> 193 case string:tokens(DateStr," ") of 194 [_WeekDay,Date,Time,_TimeZone|_Rest] -> 195 convert_rfc850_date(Date,Time); 196 _Error -> 197 bad_date 198 end. 199 200convert_rfc850_date([D1,D2,_,M,O,N,_,Y1,Y2|_Rest],[H1,H2,_Col,M1,M2,_Col,S1,S2|_Rest2])-> 201 Year=list_to_integer([50,48,Y1,Y2]), 202 Day=list_to_integer([D1,D2]), 203 Month=convert_month([M,O,N]), 204 Hour=list_to_integer([H1,H2]), 205 Min=list_to_integer([M1,M2]), 206 Sec=list_to_integer([S1,S2]), 207 {ok,{{Year,Month,Day},{Hour,Min,Sec}}}; 208convert_rfc850_date(_BadDate,_BadTime)-> 209 bad_date. 210 211convert_ascii_date([_D,_A,_Y,_SP,M,O,N,_SP,D1,D2,_SP,H1,H2,_Col,M1,M2,_Col,S1,S2,_SP,Y1,Y2,Y3,Y4|_Rest])-> 212 Year=list_to_integer([Y1,Y2,Y3,Y4]), 213 Day=case D1 of 214 $\ -> 215 list_to_integer([D2]); 216 _-> 217 list_to_integer([D1,D2]) 218 end, 219 Month=convert_month([M,O,N]), 220 Hour=list_to_integer([H1,H2]), 221 Min=list_to_integer([M1,M2]), 222 Sec=list_to_integer([S1,S2]), 223 {ok,{{Year,Month,Day},{Hour,Min,Sec}}}; 224convert_ascii_date(BadDate)-> 225 bad_date. 226convert_rfc1123_date([_D,_A,_Y,_C,_SP,D1,D2,_SP,M,O,N,_SP,Y1,Y2,Y3,Y4,_SP,H1,H2,_Col,M1,M2,_Col,S1,S2|Rest])-> 227 Year=list_to_integer([Y1,Y2,Y3,Y4]), 228 Day=list_to_integer([D1,D2]), 229 Month=convert_month([M,O,N]), 230 Hour=list_to_integer([H1,H2]), 231 Min=list_to_integer([M1,M2]), 232 Sec=list_to_integer([S1,S2]), 233 {ok,{{Year,Month,Day},{Hour,Min,Sec}}}; 234convert_rfc1123_date(BadDate)-> 235 bad_date. 236 237convert_month("Jan")->1; 238convert_month("Feb") ->2; 239convert_month("Mar") ->3; 240convert_month("Apr") ->4; 241convert_month("May") ->5; 242convert_month("Jun") ->6; 243convert_month("Jul") ->7; 244convert_month("Aug") ->8; 245convert_month("Sep") ->9; 246convert_month("Oct") ->10; 247convert_month("Nov") ->11; 248convert_month("Dec") ->12. 249 250 251%% rfc1123_date 252 253rfc1123_date() -> 254 {{YYYY,MM,DD},{Hour,Min,Sec}}=calendar:universal_time(), 255 DayNumber=calendar:day_of_the_week({YYYY,MM,DD}), 256 lists:flatten(io_lib:format("~s, ~2.2.0w ~3.s ~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT", 257 [day(DayNumber),DD,month(MM),YYYY,Hour,Min,Sec])). 258 259rfc1123_date({{YYYY,MM,DD},{Hour,Min,Sec}}) -> 260 DayNumber=calendar:day_of_the_week({YYYY,MM,DD}), 261 lists:flatten(io_lib:format("~s, ~2.2.0w ~3.s ~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT", 262 [day(DayNumber),DD,month(MM),YYYY,Hour,Min,Sec])). 263 264%% uniq 265 266uniq([]) -> 267 []; 268uniq([First,First|Rest]) -> 269 uniq([First|Rest]); 270uniq([First|Rest]) -> 271 [First|uniq(Rest)]. 272 273 274%% day 275 276day(1) -> "Mon"; 277day(2) -> "Tue"; 278day(3) -> "Wed"; 279day(4) -> "Thu"; 280day(5) -> "Fri"; 281day(6) -> "Sat"; 282day(7) -> "Sun". 283 284%% month 285 286month(1) -> "Jan"; 287month(2) -> "Feb"; 288month(3) -> "Mar"; 289month(4) -> "Apr"; 290month(5) -> "May"; 291month(6) -> "Jun"; 292month(7) -> "Jul"; 293month(8) -> "Aug"; 294month(9) -> "Sep"; 295month(10) -> "Oct"; 296month(11) -> "Nov"; 297month(12) -> "Dec". 298 299%% decode_hex 300 301decode_hex([$%,Hex1,Hex2|Rest]) -> 302 [hex2dec(Hex1)*16+hex2dec(Hex2)|decode_hex(Rest)]; 303decode_hex([First|Rest]) -> 304 [First|decode_hex(Rest)]; 305decode_hex([]) -> 306 []. 307 308hex2dec(X) when X>=$0,X=<$9 -> X-$0; 309hex2dec(X) when X>=$A,X=<$F -> X-$A+10; 310hex2dec(X) when X>=$a,X=<$f -> X-$a+10. 311 312%% decode_base64 (DEBUG STRING: QWxhZGRpbjpvcGVuIHNlc2FtZQ==) 313 314decode_base64([]) -> 315 []; 316decode_base64([Sextet1,Sextet2,$=,$=|Rest]) -> 317 Bits2x6= 318 (d(Sextet1) bsl 18) bor 319 (d(Sextet2) bsl 12), 320 Octet1=Bits2x6 bsr 16, 321 [Octet1|decode_base64(Rest)]; 322decode_base64([Sextet1,Sextet2,Sextet3,$=|Rest]) -> 323 Bits3x6= 324 (d(Sextet1) bsl 18) bor 325 (d(Sextet2) bsl 12) bor 326 (d(Sextet3) bsl 6), 327 Octet1=Bits3x6 bsr 16, 328 Octet2=(Bits3x6 bsr 8) band 16#ff, 329 [Octet1,Octet2|decode_base64(Rest)]; 330decode_base64([Sextet1,Sextet2,Sextet3,Sextet4|Rest]) -> 331 Bits4x6= 332 (d(Sextet1) bsl 18) bor 333 (d(Sextet2) bsl 12) bor 334 (d(Sextet3) bsl 6) bor 335 d(Sextet4), 336 Octet1=Bits4x6 bsr 16, 337 Octet2=(Bits4x6 bsr 8) band 16#ff, 338 Octet3=Bits4x6 band 16#ff, 339 [Octet1,Octet2,Octet3|decode_base64(Rest)]; 340decode_base64(CatchAll) -> 341 "BAD!". 342 343d(X) when X >= $A, X =<$Z -> 344 X-65; 345d(X) when X >= $a, X =<$z -> 346 X-71; 347d(X) when X >= $0, X =<$9 -> 348 X+4; 349d($+) -> 62; 350d($/) -> 63; 351d(_) -> 63. 352 353 354encode_base64([]) -> 355 []; 356encode_base64([A]) -> 357 [e(A bsr 2), e((A band 3) bsl 4), $=, $=]; 358encode_base64([A,B]) -> 359 [e(A bsr 2), e(((A band 3) bsl 4) bor (B bsr 4)), e((B band 15) bsl 2), $=]; 360encode_base64([A,B,C|Ls]) -> 361 encode_base64_do(A,B,C, Ls). 362encode_base64_do(A,B,C, Rest) -> 363 BB = (A bsl 16) bor (B bsl 8) bor C, 364 [e(BB bsr 18), e((BB bsr 12) band 63), 365 e((BB bsr 6) band 63), e(BB band 63)|encode_base64(Rest)]. 366 367e(X) when X >= 0, X < 26 -> X+65; 368e(X) when X>25, X<52 -> X+71; 369e(X) when X>51, X<62 -> X-4; 370e(62) -> $+; 371e(63) -> $/; 372e(X) -> exit({bad_encode_base64_token, X}). 373 374 375%% flatlength 376 377flatlength(List) -> 378 flatlength(List, 0). 379 380flatlength([H|T],L) when list(H) -> 381 flatlength(H,flatlength(T,L)); 382flatlength([H|T],L) when binary(H) -> 383 flatlength(T,L+size(H)); 384flatlength([H|T],L) -> 385 flatlength(T,L+1); 386flatlength([],L) -> 387 L. 388 389%% split_path 390 391split_path(Path) -> 392 case regexp:match(Path,"[\?].*\$") of 393 %% A QUERY_STRING exists! 394 {match,Start,Length} -> 395 {httpd_util:decode_hex(string:substr(Path,1,Start-1)), 396 string:substr(Path,Start,Length)}; 397 %% A possible PATH_INFO exists! 398 nomatch -> 399 split_path(Path,[]) 400 end. 401 402split_path([],SoFar) -> 403 {httpd_util:decode_hex(lists:reverse(SoFar)),[]}; 404split_path([$/|Rest],SoFar) -> 405 Path=httpd_util:decode_hex(lists:reverse(SoFar)), 406 case file:read_file_info(Path) of 407 {ok,FileInfo} when FileInfo#file_info.type == regular -> 408 {Path,[$/|Rest]}; 409 {ok,FileInfo} -> 410 split_path(Rest,[$/|SoFar]); 411 {error,Reason} -> 412 split_path(Rest,[$/|SoFar]) 413 end; 414split_path([C|Rest],SoFar) -> 415 split_path(Rest,[C|SoFar]). 416 417%% split_script_path 418 419split_script_path(Path) -> 420 case split_script_path(Path, []) of 421 {Script, AfterPath} -> 422 {PathInfo, QueryString} = pathinfo_querystring(AfterPath), 423 {Script, {PathInfo, QueryString}}; 424 not_a_script -> 425 not_a_script 426 end. 427 428pathinfo_querystring(Str) -> 429 pathinfo_querystring(Str, []). 430pathinfo_querystring([], SoFar) -> 431 {lists:reverse(SoFar), []}; 432pathinfo_querystring([$?|Rest], SoFar) -> 433 {lists:reverse(SoFar), Rest}; 434pathinfo_querystring([C|Rest], SoFar) -> 435 pathinfo_querystring(Rest, [C|SoFar]). 436 437split_script_path([$?|QueryString], SoFar) -> 438 Path = httpd_util:decode_hex(lists:reverse(SoFar)), 439 case file:read_file_info(Path) of 440 {ok,FileInfo} when FileInfo#file_info.type == regular -> 441 {Path, [$?|QueryString]}; 442 {ok,FileInfo} -> 443 not_a_script; 444 {error,Reason} -> 445 not_a_script 446 end; 447split_script_path([], SoFar) -> 448 Path = httpd_util:decode_hex(lists:reverse(SoFar)), 449 case file:read_file_info(Path) of 450 {ok,FileInfo} when FileInfo#file_info.type == regular -> 451 {Path, []}; 452 {ok,FileInfo} -> 453 not_a_script; 454 {error,Reason} -> 455 not_a_script 456 end; 457split_script_path([$/|Rest], SoFar) -> 458 Path = httpd_util:decode_hex(lists:reverse(SoFar)), 459 case file:read_file_info(Path) of 460 {ok, FileInfo} when FileInfo#file_info.type == regular -> 461 {Path, [$/|Rest]}; 462 {ok, _FileInfo} -> 463 split_script_path(Rest, [$/|SoFar]); 464 {error, _Reason} -> 465 split_script_path(Rest, [$/|SoFar]) 466 end; 467split_script_path([C|Rest], SoFar) -> 468 split_script_path(Rest,[C|SoFar]). 469 470%% suffix 471 472suffix(Path) -> 473 case filename:extension(Path) of 474 [] -> 475 []; 476 Extension -> 477 tl(Extension) 478 end. 479 480%% to_upper 481 482to_upper([C|Cs]) when C >= $a, C =< $z -> 483 [C-($a-$A)|to_upper(Cs)]; 484to_upper([C|Cs]) -> 485 [C|to_upper(Cs)]; 486to_upper([]) -> 487 []. 488 489%% to_lower 490 491to_lower([C|Cs]) when C >= $A, C =< $Z -> 492 [C+($a-$A)|to_lower(Cs)]; 493to_lower([C|Cs]) -> 494 [C|to_lower(Cs)]; 495to_lower([]) -> 496 []. 497 498 499%% strip 500strip(Value)-> 501 lists:reverse(remove_ws(lists:reverse(remove_ws(Value)))). 502 503remove_ws([$\s|Rest])-> 504 remove_ws(Rest); 505remove_ws([$\t|Rest]) -> 506 remove_ws(Rest); 507remove_ws(Rest) -> 508 Rest. 509 510%% split 511 512split(String,RegExp,Limit) -> 513 case regexp:parse(RegExp) of 514 {error,Reason} -> 515 {error,Reason}; 516 {ok,_} -> 517 {ok,do_split(String,RegExp,Limit)} 518 end. 519 520do_split(String,RegExp,1) -> 521 [String]; 522 523do_split(String,RegExp,Limit) -> 524 case regexp:first_match(String,RegExp) of 525 {match,Start,Length} -> 526 [string:substr(String,1,Start-1)| 527 do_split(lists:nthtail(Start+Length-1,String),RegExp,Limit-1)]; 528 nomatch -> 529 [String] 530 end. 531 532%% header 533header(StatusCode,Date)when list(Date)-> 534 header(StatusCode,"text/plain",false); 535 536header(StatusCode, PersistentConnection) when integer(StatusCode)-> 537 Date = rfc1123_date(), 538 Connection = 539 case PersistentConnection of 540 true -> 541 ""; 542 _ -> 543 "Connection: close \r\n" 544 end, 545 io_lib:format("HTTP/1.1 ~w ~s \r\nDate: ~s\r\nServer: ~s\r\n~s", 546 [StatusCode, httpd_util:reason_phrase(StatusCode), 547 Date, ?SERVER_SOFTWARE, Connection]). 548 549%%---------------------------------------------------------------------- 550 551header(StatusCode, MimeType, Date) when list(Date) -> 552 header(StatusCode, MimeType, false,rfc1123_date()); 553 554 555header(StatusCode, MimeType, PersistentConnection) when integer(StatusCode) -> 556 header(StatusCode, MimeType, PersistentConnection,rfc1123_date()). 557 558 559%%---------------------------------------------------------------------- 560 561header(416, MimeType,PersistentConnection,Date)-> 562 Connection = 563 case PersistentConnection of 564 true -> 565 ""; 566 _ -> 567 "Connection: close \r\n" 568 end, 569 io_lib:format("HTTP/1.1 ~w ~s \r\nDate: ~s\r\nServer: ~s\r\n" 570 "Content-Range:bytes *" 571 "Content-Type: ~s\r\n~s", 572 [416, httpd_util:reason_phrase(416), 573 Date, ?SERVER_SOFTWARE, MimeType, Connection]); 574 575 576header(StatusCode, MimeType,PersistentConnection,Date) when integer(StatusCode)-> 577 Connection = 578 case PersistentConnection of 579 true -> 580 ""; 581 _ -> 582 "Connection: close \r\n" 583 end, 584 io_lib:format("HTTP/1.1 ~w ~s \r\nDate: ~s\r\nServer: ~s\r\n" 585 "Content-Type: ~s\r\n~s", 586 [StatusCode, httpd_util:reason_phrase(StatusCode), 587 Date, ?SERVER_SOFTWARE, MimeType, Connection]). 588 589 590 591%% make_name/2, make_name/3 592%% Prefix -> string() 593%% First part of the name, e.g. "httpd" 594%% Addr -> {A,B,C,D} | string() | undefined 595%% The address part of the name. 596%% e.g. "123.234.55.66" or {123,234,55,66} or "otp.ericsson.se" 597%% for a host address or undefined if local host. 598%% Port -> integer() 599%% Last part of the name, such as the HTTPD server port 600%% number (80). 601%% Postfix -> Any string that will be added last to the name 602%% 603%% Example: 604%% make_name("httpd","otp.ericsson.se",80) => httpd__otp_ericsson_se__80 605%% make_name("httpd",undefined,8088) => httpd_8088 606 607make_name(Prefix,Port) -> 608 make_name(Prefix,undefined,Port,""). 609 610make_name(Prefix,Addr,Port) -> 611 make_name(Prefix,Addr,Port,""). 612 613make_name(Prefix,"*",Port,Postfix) -> 614 make_name(Prefix,undefined,Port,Postfix); 615 616make_name(Prefix,any,Port,Postfix) -> 617 make_name1(io_lib:format("~s_~w~s",[Prefix,Port,Postfix])); 618 619make_name(Prefix,undefined,Port,Postfix) -> 620 make_name1(io_lib:format("~s_~w~s",[Prefix,Port,Postfix])); 621 622make_name(Prefix,Addr,Port,Postfix) -> 623 NameString = 624 Prefix ++ "__" ++ make_name2(Addr) ++ "__" ++ 625 integer_to_list(Port) ++ Postfix, 626 make_name1(NameString). 627 628make_name1(String) -> 629 list_to_atom(lists:flatten(String)). 630 631make_name2({A,B,C,D}) -> 632 io_lib:format("~w_~w_~w_~w",[A,B,C,D]); 633make_name2(Addr) -> 634 search_and_replace(Addr,$.,$_). 635 636search_and_replace(S,A,B) -> 637 Fun = fun(What) -> 638 case What of 639 A -> B; 640 O -> O 641 end 642 end, 643 lists:map(Fun,S). 644 645 646 647%%---------------------------------------------------------------------- 648%% Converts a string that constists of 0-9,A-F,a-f to a 649%% integer 650%%---------------------------------------------------------------------- 651 652hexlist_to_integer([])-> 653 empty; 654 655 656%%When the string only contains one value its eaasy done. 657%% 0-9 658hexlist_to_integer([Size]) when Size>=48 , Size=<57 -> 659 Size-48; 660%% A-F 661hexlist_to_integer([Size]) when Size>=65 , Size=<70 -> 662 Size-55; 663%% a-f 664hexlist_to_integer([Size]) when Size>=97 , Size=<102 -> 665 Size-87; 666hexlist_to_integer([Size]) -> 667 not_a_num; 668 669hexlist_to_integer(Size) -> 670 Len=string:span(Size,"1234567890abcdefABCDEF"), 671 hexlist_to_integer2(Size,16 bsl (4 *(Len-2)),0). 672 673hexlist_to_integer2([],_Pos,Sum)-> 674 Sum; 675hexlist_to_integer2([HexVal|HexString],Pos,Sum)when HexVal>=48,HexVal=<57-> 676 hexlist_to_integer2(HexString,Pos bsr 4,Sum+((HexVal-48)*Pos)); 677 678hexlist_to_integer2([HexVal|HexString],Pos,Sum)when HexVal>=65,HexVal=<70-> 679 hexlist_to_integer2(HexString,Pos bsr 4,Sum+((HexVal-55)*Pos)); 680 681hexlist_to_integer2([HexVal|HexString],Pos,Sum)when HexVal>=97,HexVal=<102-> 682 hexlist_to_integer2(HexString,Pos bsr 4,Sum+((HexVal-87)*Pos)); 683 684hexlist_to_integer2(_AfterHexString,_Pos,Sum)-> 685 Sum. 686 687%%---------------------------------------------------------------------- 688%%Converts an integer to an hexlist 689%%---------------------------------------------------------------------- 690encode_hex(Num)-> 691 integer_to_hexlist(Num). 692 693 694integer_to_hexlist(Num)-> 695 integer_to_hexlist(Num,getSize(Num),[]). 696 697integer_to_hexlist(Num,Pot,Res) when Pot<0 -> 698 convert_to_ascii([Num|Res]); 699 700integer_to_hexlist(Num,Pot,Res) -> 701 Position=(16 bsl (Pot*4)), 702 PosVal=Num div Position, 703 integer_to_hexlist(Num-(PosVal*Position),Pot-1,[PosVal|Res]). 704convert_to_ascii(RevesedNum)-> 705 convert_to_ascii(RevesedNum,[]). 706 707convert_to_ascii([],Num)-> 708 Num; 709convert_to_ascii([Num|Reversed],Number)when Num>-1, Num<10 -> 710 convert_to_ascii(Reversed,[Num+48|Number]); 711convert_to_ascii([Num|Reversed],Number)when Num>9, Num<16 -> 712 convert_to_ascii(Reversed,[Num+55|Number]); 713convert_to_ascii(NumReversed,Number) -> 714 error. 715 716 717 718getSize(Num)-> 719 getSize(Num,0). 720 721getSize(Num,Pot)when Num<(16 bsl(Pot *4)) -> 722 Pot-1; 723 724getSize(Num,Pot) -> 725 getSize(Num,Pot+1). 726 727 728 729 730 731create_etag(FileInfo)-> 732 create_etag(FileInfo#file_info.mtime,FileInfo#file_info.size). 733 734create_etag({{Year,Month,Day},{Hour,Min,Sec}},Size)-> 735 create_part([Year,Month,Day,Hour,Min,Sec])++io_lib:write(Size); 736 737create_etag(FileInfo,Size)-> 738 create_etag(FileInfo#file_info.mtime,Size). 739 740create_part(Values)-> 741 lists:map(fun(Val0)-> 742 Val=Val0 rem 60, 743 if 744 Val=<25 -> 745 65+Val; % A-Z 746 Val=<50 -> 747 72+Val; % a-z 748 %%Since no date s 749 true -> 750 Val-3 751 end 752 end,Values). 753 754 755 756%%---------------------------------------------------------------------- 757%%Function that controls whether a response is generated or not 758%%---------------------------------------------------------------------- 759response_generated(Info)-> 760 case httpd_util:key1search(Info#mod.data,status) of 761 %% A status code has been generated! 762 {StatusCode,PhraseArgs,Reason}-> 763 true; 764 %%No status code control repsonsxe 765 undefined -> 766 case httpd_util:key1search(Info#mod.data, response) of 767 %% No response has been generated! 768 undefined -> 769 false; 770 %% A response has been generated or sent! 771 Response -> 772 true 773 end 774 end. 775