Anonymous avatar Anonymous committed 14365a1 Merge

merge

Comments (0)

Files changed (6)

deps/mochiweb/src/mochijson.erl

            end,
     [NewC | json_encode_string_utf8_1(Cs)];
 json_encode_string_utf8_1(All=[C | _]) when C >= 16#80, C =< 16#10FFFF ->
-    json_encode_string_unicode(xmerl_ucs:from_utf8(All));
+    [?Q | Rest] = json_encode_string_unicode(xmerl_ucs:from_utf8(All)),
+    Rest;
 json_encode_string_utf8_1([]) ->
     "\"".
 
     end.
 
 test_all() ->
+    test_issue33(),
     test_one(e2j_test_vec(utf8), 1).
 
+test_issue33() ->
+    %% http://code.google.com/p/mochiweb/issues/detail?id=33
+    Js = {struct, [{"key", [194, 163]}]},
+    Encoder = encoder([{input_encoding, utf8}]),
+    "{\"key\":\"\\u00a3\"}" = lists:flatten(Encoder(Js)).
+
 test_one([], _N) ->
     %% io:format("~p tests passed~n", [N-1]),
     ok;

deps/mochiweb/src/mochijson2.erl

 %% @type json_term() = json_string() | json_number() | json_array() |
 %%                     json_object()
 
--record(encoder, {handler=null}).
+-record(encoder, {handler=null,
+                  utf8=false}).
 
 -record(decoder, {object_hook=null,
                   offset=0,
 
 %% @spec encoder([encoder_option()]) -> function()
 %% @doc Create an encoder/1 with the given options.
+%% @type encoder_option() = handler_option() | utf8_option()
+%% @type utf8_option() = boolean(). Emit unicode as utf8 (default - false)
 encoder(Options) ->
     State = parse_encoder_options(Options, #encoder{}),
     fun (O) -> json_encode(O, State) end.
 parse_encoder_options([], State) ->
     State;
 parse_encoder_options([{handler, Handler} | Rest], State) ->
-    parse_encoder_options(Rest, State#encoder{handler=Handler}).
+    parse_encoder_options(Rest, State#encoder{handler=Handler});
+parse_encoder_options([{utf8, Switch} | Rest], State) ->
+    parse_encoder_options(Rest, State#encoder{utf8=Switch}).
 
 parse_decoder_options([], State) ->
     State;
     [$, | Acc1] = lists:foldl(F, "{", Props),
     lists:reverse([$\} | Acc1]).
 
-json_encode_string(A, _State) when is_atom(A) ->
+json_encode_string(A, State) when is_atom(A) ->
     L = atom_to_list(A),
     case json_string_is_safe(L) of
         true ->
             [?Q, L, ?Q];
         false ->
-            json_encode_string_unicode(xmerl_ucs:from_utf8(L), [?Q])
+            json_encode_string_unicode(xmerl_ucs:from_utf8(L), State, [?Q])
     end;
-json_encode_string(B, _State) when is_binary(B) ->
+json_encode_string(B, State) when is_binary(B) ->
     case json_bin_is_safe(B) of
         true ->
             [?Q, B, ?Q];
         false ->
-            json_encode_string_unicode(xmerl_ucs:from_utf8(B), [?Q])
+            json_encode_string_unicode(xmerl_ucs:from_utf8(B), State, [?Q])
     end;
 json_encode_string(I, _State) when is_integer(I) ->
     [?Q, integer_to_list(I), ?Q];
-json_encode_string(L, _State) when is_list(L) ->
+json_encode_string(L, State) when is_list(L) ->
     case json_string_is_safe(L) of
         true ->
             [?Q, L, ?Q];
         false ->
-            json_encode_string_unicode(L, [?Q])
+            json_encode_string_unicode(L, State, [?Q])
     end.
 
 json_string_is_safe([]) ->
             false
     end.
 
-json_encode_string_unicode([], Acc) ->
+json_encode_string_unicode([], _State, Acc) ->
     lists:reverse([$\" | Acc]);
-json_encode_string_unicode([C | Cs], Acc) ->
+json_encode_string_unicode([C | Cs], State, Acc) ->
     Acc1 = case C of
                ?Q ->
                    [?Q, $\\ | Acc];
                    [$r, $\\ | Acc];
                $\t ->
                    [$t, $\\ | Acc];
-               C when C >= 0, C < $\s; C >= 16#7f, C =< 16#10FFFF ->
+               C when C >= 0, C < $\s ->
+                   [unihex(C) | Acc];
+               C when C >= 16#7f, C =< 16#10FFFF, State#encoder.utf8 ->
+                   [xmerl_ucs:to_utf8(C) | Acc];
+               C when  C >= 16#7f, C =< 16#10FFFF, not State#encoder.utf8 ->
                    [unihex(C) | Acc];
                C when C < 16#7f ->
                    [C | Acc];
                _ ->
                    exit({json_encode, {bad_char, C}})
            end,
-    json_encode_string_unicode(Cs, Acc1).
+    json_encode_string_unicode(Cs, State, Acc1).
 
 hexdigit(C) when C >= 0, C =< 9 ->
     C + $0;
 
 test_all() ->
     [1199344435545.0, 1] = decode(<<"[1199344435545.0,1]">>),
+    test_encoder_utf8(),
     test_one(e2j_test_vec(utf8), 1).
 
 test_one([], _N) ->
      {[-123, <<"foo">>, obj_from_list([{<<"bar">>, []}]), null],
       "[-123,\"foo\",{\"bar\":[]},null]"}
     ].
+
+%% test utf8 encoding
+test_encoder_utf8() ->
+    %% safe conversion case (default)
+    [34,"\\u0001","\\u0442","\\u0435","\\u0441","\\u0442",34] = 
+        encode(<<1,"\321\202\320\265\321\201\321\202">>),
+
+    %% raw utf8 output (optional)
+    Enc = mochijson2:encoder([{utf8, true}]),
+    [34,"\\u0001",[209,130],[208,181],[209,129],[209,130],34] =
+        Enc(<<1,"\321\202\320\265\321\201\321\202">>).

deps/mochiweb/src/mochiweb_cookies.erl

 %% @spec cookie(Key::string(), Value::string(), Options::[Option]) -> header() 
 %% where Option = {max_age, integer()} | {local_time, {date(), time()}} 
 %%                | {domain, string()} | {path, string()}
-%%                | {secure, true | false}
+%%                | {secure, true | false} | {http_only, true | false}
 %%
 %% @doc Generate a Set-Cookie header field tuple.
 cookie(Key, Value, Options) ->
             Path ->
                 ["; Path=", quote(Path)]
         end,
-    CookieParts = [Cookie, ExpiresPart, SecurePart, DomainPart, PathPart],
+    HttpOnlyPart =
+        case proplists:get_value(http_only, Options) of
+            true ->
+                "; HttpOnly";
+            _ ->
+                ""
+        end,
+    CookieParts = [Cookie, ExpiresPart, SecurePart, DomainPart, PathPart, HttpOnlyPart],
     {"Set-Cookie", lists:flatten(CookieParts)}.
 
 

deps/mochiweb/src/mochiweb_html.erl

      {data, <<" A= B <= C ">>, false},
      {end_tag, <<"script">>}] =
         tokens(<<"<script type=\"text/javascript\"> A= B <= C </script>">>),
+    [{start_tag, <<"script">>, [{<<"type">>, <<"text/javascript">>}], false},
+     {data, <<" A= B <= C ">>, false},
+     {end_tag, <<"script">>}] =
+        tokens(<<"<script type =\"text/javascript\"> A= B <= C </script>">>),
+    [{start_tag, <<"script">>, [{<<"type">>, <<"text/javascript">>}], false},
+     {data, <<" A= B <= C ">>, false},
+     {end_tag, <<"script">>}] =
+        tokens(<<"<script type = \"text/javascript\"> A= B <= C </script>">>),
+    [{start_tag, <<"script">>, [{<<"type">>, <<"text/javascript">>}], false},
+     {data, <<" A= B <= C ">>, false},
+     {end_tag, <<"script">>}] =
+        tokens(<<"<script type= \"text/javascript\"> A= B <= C </script>">>),
     [{start_tag, <<"textarea">>, [], false},
      {data, <<"<html></body>">>, false},
      {end_tag, <<"textarea">>}] =
     O = S1#decoder.offset,
     case B of
         <<_:O/binary, "=", _/binary>> ->
-            tokenize_word_or_literal(B, ?INC_COL(S1));
+            S2 = skip_whitespace(B, ?INC_COL(S1)),
+            tokenize_word_or_literal(B, S2);
         _ ->
             {Attr, S1}
     end.

deps/mochiweb/src/mochiweb_request.erl

 recv_body(MaxBody) ->
     % we could use a sane constant for max chunk size
     Body = stream_body(?MAX_RECV_BODY, fun
-        ({0, _ChunkedFooter}, {_LengthAcc, BinAcc}) -> 
+        ({0, _ChunkedFooter}, {_LengthAcc, BinAcc}) ->
             iolist_to_binary(lists:reverse(BinAcc));
         ({Length, Bin}, {LengthAcc, BinAcc}) ->
             NewLength = Length + LengthAcc,
             if NewLength > MaxBody ->
                 exit({body_too_large, chunked});
-            true -> 
+            true ->
                 {NewLength, [Bin | BinAcc]}
             end
         end, {0, []}, MaxBody),
 
 stream_body(MaxChunkSize, ChunkFun, FunState) ->
     stream_body(MaxChunkSize, ChunkFun, FunState, undefined).
-    
+
 stream_body(MaxChunkSize, ChunkFun, FunState, MaxBodyLength) ->
-
-    case get_header_value("expect") of
+    Expect = case get_header_value("expect") of
+                 undefined ->
+                     undefined;
+                 Value when is_list(Value) ->
+                     string:to_lower(Value)
+             end,
+    case Expect of
         "100-continue" ->
             start_raw_response({100, gb_trees:empty()});
         _Else ->
                 exit({body_too_large, content_length});
             _ ->
                 stream_unchunked_body(Length, MaxChunkSize, ChunkFun, FunState)
-            end;     
+            end;
         Length ->
             exit({length_not_integer, Length})
     end.
 
 read_sub_chunks(Length, _MaxChunkSize, Fun, FunState) ->
     Fun({Length, read_chunk(Length)}, FunState).
-    
+
 %% @spec serve_file(Path, DocRoot) -> Response
 %% @doc Serve a file relative to DocRoot.
 serve_file(Path, DocRoot) ->
     %% valid, multiple range
     io:format("Testing parse_range_request with valid multiple ranges~n"),
     io:format("1"),
-    [{20, 30}, {50, 100}, {110, 200}] = 
+    [{20, 30}, {50, 100}, {110, 200}] =
         parse_range_request("bytes=20-30,50-100,110-200"),
     io:format("2"),
-    [{20, none}, {50, 100}, {none, 200}] = 
+    [{20, none}, {50, 100}, {none, 200}] =
         parse_range_request("bytes=20-,50-100,-200"),
     io:format(".. ok~n"),
-    
+
     %% no ranges
     io:format("Testing out parse_range_request with no ranges~n"),
     io:format("1"),
     [] = parse_range_request("bytes="),
     io:format(".. ok~n"),
-    
+
     Body = <<"012345678901234567890123456789012345678901234567890123456789">>,
     BodySize = size(Body), %% 60
     BodySize = 60,
     io:format("4"),
     {30, 30} = range_skip_length({30, none}, BodySize), %% 30-
     io:format(".. ok ~n"),
-    
+
     %% valid edge cases for range_skip_length
     io:format("Testing out range_skip_length on valid edge case ranges~n"),
     io:format("1"),
     invalid_range = range_skip_length({BodySize, none}, BodySize),
     io:format(".. ok ~n"),
     ok.
-    
+

deps/mochiweb/src/mochiweb_skel.erl

     "skel".
 
 skelcopy(Src, DestDir, Name, LDst) ->
-    {ok, Dest, _} = regexp:gsub(filename:basename(Src), skel(), Name),
+    Dest = re:replace(filename:basename(Src), skel(), Name,
+                      [global, {return, list}]),
     case file:read_file_info(Src) of
         {ok, #file_info{type=directory, mode=Mode}} ->
             Dir = DestDir ++ "/" ++ Dest,
         {ok, #file_info{type=regular, mode=Mode}} ->
             OutFile = filename:join(DestDir, Dest),
             {ok, B} = file:read_file(Src),
-            {ok, S, _} = regexp:gsub(binary_to_list(B), skel(), Name),
+            S = re:replace(binary_to_list(B), skel(), Name,
+                           [{return, list}, global]),
             ok = file:write_file(OutFile, list_to_binary(S)),
             ok = file:write_file_info(OutFile, #file_info{mode=Mode}),
             io:format("    ~s~n", [filename:basename(Src)]),
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.