@@ -12,15 +12,14 @@ defmodule URI do
12
12
"""
13
13
14
14
defstruct scheme: nil ,
15
- path: "" ,
15
+ path: nil ,
16
16
query: nil ,
17
17
fragment: nil ,
18
18
authority: nil ,
19
19
userinfo: nil ,
20
20
host: nil ,
21
21
port: nil
22
22
23
- # TODO: Remove nil from path when we fully deprecate URI.parse on Elixir v1.17
24
23
@ type t :: % __MODULE__ {
25
24
authority: authority ,
26
25
fragment: nil | binary ,
@@ -480,12 +479,13 @@ defmodule URI do
480
479
Creates a new URI struct from a URI or a string.
481
480
482
481
If a `%URI{}` struct is given, it returns `{:ok, uri}`. If a string is
483
- given, it will parse it and returns `{:ok, uri}`. If the string is
484
- invalid, it returns `{:error, part}` instead, with the invalid part of the URI.
482
+ given, it will parse and validate it. If the string is valid, it returns
483
+ `{:ok, uri}`, otherwise it returns `{:error, part}` with the invalid part
484
+ of the URI. For parsing URIs without further validation, see `parse/1`.
485
485
486
486
This function can parse both absolute and relative URLs. You can check
487
487
if a URI is absolute or relative by checking if the `scheme` field is
488
- `nil` or not. All fields may be `nil`, except for the `path`.
488
+ `nil` or not.
489
489
490
490
When a URI is given without a port, the value returned by `URI.default_port/1`
491
491
for the URI's scheme is used for the `:port` field. The scheme is also
@@ -552,7 +552,7 @@ defmodule URI do
552
552
{:ok, %URI{
553
553
fragment: nil,
554
554
host: nil,
555
- path: "" ,
555
+ path: nil ,
556
556
port: 443,
557
557
query: "query",
558
558
scheme: "https",
@@ -634,6 +634,8 @@ defmodule URI do
634
634
end
635
635
end
636
636
637
+ defp uri_from_map ( % { path: "" } = map ) , do: uri_from_map ( % { map | path: nil } )
638
+
637
639
defp uri_from_map ( map ) do
638
640
uri = Map . merge ( % URI { } , map )
639
641
@@ -658,29 +660,106 @@ defmodule URI do
658
660
end
659
661
660
662
@ doc """
661
- Parses a well-formed URI into its components.
663
+ Parses a URI into its components, without further validation .
662
664
663
- This function is deprecated as it fails to raise in case of invalid URIs.
664
- Use `URI.new!/1` or `URI.new/1` instead. In case you want to mimic the
665
- behaviour of this function, you can do:
665
+ This function can parse both absolute and relative URLs. You can check
666
+ if a URI is absolute or relative by checking if the `scheme` field is
667
+ nil or not. Furthermore, this function expects both absolute and
668
+ relative URIs to be well-formed and does not perform any validation.
669
+ See the "Examples" section below. Use `new/1` if you want more strict
670
+ validation.
666
671
667
- case URI.new(path) do
668
- {:ok, uri} -> uri
669
- {:error, _} -> %URI{path: path}
670
- end
672
+ When a URI is given without a port, the value returned by `URI.default_port/1`
673
+ for the URI's scheme is used for the `:port` field. The scheme is also
674
+ normalized to lowercase.
675
+
676
+ If a `%URI{}` struct is given to this function, this function returns it
677
+ unmodified.
678
+
679
+ > Note: this function sets the field :authority for backwards
680
+ > compatibility reasons but it is deprecated.
681
+
682
+ ## Examples
683
+
684
+ iex> URI.parse("https://elixir-lang.org/")
685
+ %URI{
686
+ authority: "elixir-lang.org",
687
+ fragment: nil,
688
+ host: "elixir-lang.org",
689
+ path: "/",
690
+ port: 443,
691
+ query: nil,
692
+ scheme: "https",
693
+ userinfo: nil
694
+ }
695
+
696
+ iex> URI.parse("//elixir-lang.org/")
697
+ %URI{
698
+ authority: "elixir-lang.org",
699
+ fragment: nil,
700
+ host: "elixir-lang.org",
701
+ path: "/",
702
+ port: nil,
703
+ query: nil,
704
+ scheme: nil,
705
+ userinfo: nil
706
+ }
707
+
708
+ iex> URI.parse("/foo/bar")
709
+ %URI{
710
+ authority: nil,
711
+ fragment: nil,
712
+ host: nil,
713
+ path: "/foo/bar",
714
+ port: nil,
715
+ query: nil,
716
+ scheme: nil,
717
+ userinfo: nil
718
+ }
719
+
720
+ iex> URI.parse("foo/bar")
721
+ %URI{
722
+ authority: nil,
723
+ fragment: nil,
724
+ host: nil,
725
+ path: "foo/bar",
726
+ port: nil,
727
+ query: nil,
728
+ scheme: nil,
729
+ userinfo: nil
730
+ }
671
731
672
- There are two differencws in the behaviour of this function compared to
673
- `URI.new/1` :
732
+ In contrast to `URI.new/1`, this function will parse poorly-formed
733
+ URIs, for example :
674
734
675
- * This function sets the deprecated authority field
735
+ iex> URI.parse("/invalid_greater_than_in_path/>")
736
+ %URI{
737
+ authority: nil,
738
+ fragment: nil,
739
+ host: nil,
740
+ path: "/invalid_greater_than_in_path/>",
741
+ port: nil,
742
+ query: nil,
743
+ scheme: nil,
744
+ userinfo: nil
745
+ }
746
+
747
+ Another example is a URI with brackets in query strings. It is accepted
748
+ by `parse/1` but it will be refused by `new/1`:
676
749
677
- * This function sets the path to `nil` when it is empty,
678
- while `new/1` consider the path always exists and sets it
679
- to an empty string
750
+ iex> URI.parse("/?foo[bar]=baz")
751
+ %URI{
752
+ authority: nil,
753
+ fragment: nil,
754
+ host: nil,
755
+ path: "/",
756
+ port: nil,
757
+ query: "foo[bar]=baz",
758
+ scheme: nil,
759
+ userinfo: nil
760
+ }
680
761
681
762
"""
682
- # TODO: Deprecate me at least on v1.17
683
- @ doc deprecated: "Use URI.new/1 or URI.new!/1 instead"
684
763
@ spec parse ( t | binary ) :: t
685
764
def parse ( % URI { } = uri ) , do: uri
686
765
@@ -813,6 +892,7 @@ defmodule URI do
813
892
% { rel | scheme: base . scheme , path: remove_dot_segments_from_path ( rel . path ) }
814
893
end
815
894
895
+ # TODO: Check only for nils in future versions
816
896
def merge ( % URI { } = base , % URI { path: rel_path } = rel ) when rel_path in [ "" , nil ] do
817
897
% { base | query: rel . query || base . query , fragment: rel . fragment }
818
898
end
@@ -826,9 +906,7 @@ defmodule URI do
826
906
merge ( parse ( base ) , parse ( rel ) )
827
907
end
828
908
829
- # TODO: Deprecate me on Elixir v1.19
830
909
defp merge_paths ( nil , rel_path ) , do: merge_paths ( "/" , rel_path )
831
- defp merge_paths ( "" , rel_path ) , do: merge_paths ( "/" , rel_path )
832
910
defp merge_paths ( _ , "/" <> _ = rel_path ) , do: remove_dot_segments_from_path ( rel_path )
833
911
834
912
defp merge_paths ( base_path , rel_path ) do
868
946
869
947
defimpl String.Chars , for: URI do
870
948
def to_string ( % { host: host , path: path } = uri )
871
- when host != nil and path != "" and binary_part ( path , 0 , 1 ) != "/" do
949
+ when host != nil and is_binary ( path ) and
950
+ path != "" and binary_part ( path , 0 , 1 ) != "/" do
872
951
raise ArgumentError ,
873
952
":path in URI must be empty or an absolute path if URL has a :host, got: #{ inspect ( uri ) } "
874
953
end
0 commit comments