Skip to content

Commit 4bd3fe5

Browse files
committed
DataURI parsing and creation
1 parent dce395c commit 4bd3fe5

File tree

9 files changed

+168
-1
lines changed

9 files changed

+168
-1
lines changed

Project.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
33
authors = ["Jacob Quinn", "Sam O'Connor", "contributors: https://github.com/JuliaWeb/URIs.jl/graphs/contributors"]
44
version = "1.5.1"
55

6+
[deps]
7+
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
8+
69
[compat]
710
julia = "1.6"
811

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Documentation (stable)][docs-stable-img]][docs-stable-url] [![Documentation (dev)][docs-dev-img]][docs-dev-url] [![Build Status](https://github.com/JuliaWeb/URIs.jl/workflows/CI/badge.svg)](https://github.com/JuliaWeb/URIs.jl/actions)
44

55
`URIs` is a Julia package for parsing and working with Uniform Resource
6-
Identifiers, as defined in [RFC 3986](https://www.ietf.org/rfc/rfc3986.txt).
6+
Identifiers, as defined in [RFC 3986](https://www.ietf.org/rfc/rfc3986.txt) and Data URI, as defined in [RFC 2397](https://datatracker.ietf.org/doc/html/rfc2397).
77

88
Read the [**stable documentation** on
99
JuliaHub][docs-stable-url], or see the [development

docs/src/index.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
`URIs` is a Julia package for parsing and working with Uniform Resource
44
Identifiers, as defined in [RFC 3986](https://www.ietf.org/rfc/rfc3986.txt).
5+
It also supports data URI as defined in [RFC 2397](https://datatracker.ietf.org/doc/html/rfc2397).
56

67
## Tutorial
78

9+
### URI
810
```@meta
911
DocTestSetup = quote
1012
using URIs
@@ -48,6 +50,23 @@ Dict{String,String} with 2 entries:
4850
"y" => "hi"
4951
```
5052

53+
### Data URI
54+
55+
```@meta
56+
DocTestSetup = quote
57+
using URIs
58+
end
59+
```
60+
61+
Parsing Data URIs from a string can be done with the [`DataURI`](@ref) constructor:
62+
63+
```jldoctest
64+
julia> u = DataURI("data:,A%20brief%20note")
65+
DataURI("data:,A%20brief%20note")
66+
```
67+
68+
See reference and unit tests for more usage.
69+
5170
## Reference
5271

5372
```@docs
@@ -61,5 +80,7 @@ escapepath
6180
resolvereference
6281
URIs.splitpath
6382
Base.isvalid(::URI)
83+
DataURI
84+
getdata
6485
```
6586

src/URIs.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export URI,
44
queryparams, queryparampairs, absuri, splitfilepath,
55
escapeuri, unescapeuri, escapepath,
66
resolvereference
7+
export DataURI, getdata
78

89
import Base.==
910

@@ -703,6 +704,7 @@ function __init__()
703704
return
704705
end
705706

707+
include("data_uri.jl")
706708
include("deprecate.jl")
707709

708710
end # module

src/data_uri.jl

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using Base64
2+
3+
const DATA_URI_PATTERNS = [
4+
r"data:(?<mediatype>[^;]+)(?:;(?<parameters>.+))?,(?<data>.+)",
5+
r"data:,(?<data>.+)"
6+
]
7+
8+
"""
9+
DataURI(; mediatype="", encode=false, data="")
10+
DataURI(str) = parse(DataURI, str::String)
11+
12+
A type representing a Data URI (e.g. a data URL scheme as defined in RFC 2397). Can be constructed from distinct parts using the various
13+
supported keyword arguments, or from a string.
14+
"""
15+
struct DataURI
16+
uri::String
17+
mediatype::DataType
18+
isbase64::Bool
19+
data::SubString{String}
20+
parameters::Vector{Pair{String, String}}
21+
22+
end
23+
24+
function DataURI(; mediatype=MIME"text/plain", encoded=false, data="", parameters=Pair{String, String}[])
25+
base64 = encoded ? ";base64" : ""
26+
s_parameters = ""
27+
for (key, value) in parameters
28+
s_parameters *= ";$(key)=$(value)"
29+
end
30+
s_mediatype = string(mediatype.parameters[1])
31+
uri = "data:$(s_mediatype)$(s_parameters)$(base64),$(data)"
32+
DataURI(uri, mediatype, encoded, data, parameters)
33+
end
34+
35+
function DataURI(str)
36+
m = match(DATA_URI_PATTERNS[1], str)
37+
if !isnothing(m)
38+
groups = m.captures
39+
mediatype, parameters, data = groups
40+
mime = MIME{Symbol(mediatype)}
41+
isbase64 = endswith(parameters, "base64")
42+
_parameters = filter(p -> p != "base64", split(parameters, ";"))
43+
parameters = Pair{String, String}[]
44+
for p in _parameters
45+
key, value = split(p, "=")
46+
push!(parameters, key => value)
47+
end
48+
else
49+
m = match(DATA_URI_PATTERNS[2], str)
50+
data, = m.captures
51+
mime = MIME""
52+
isbase64 = false
53+
parameters = Pair{String, String}[]
54+
end
55+
DataURI(str, mime, isbase64, data, parameters)
56+
end
57+
58+
function getdata(data_uri::DataURI)
59+
data_uri.isbase64 ? base64decode(data_uri.data) : data_uri.data
60+
end

test/data_uri.jl

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using Test
2+
3+
const larry = "data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7"
4+
const greek_characters = "data:text/plain;charset=iso-8859-7,%be%fg%be"
5+
const brief_note = "data:,A%20brief%20note"
6+
7+
8+
@testset "Data URI" begin
9+
@testset "parsing" begin
10+
@testset "larry" begin
11+
data_uri = DataURI(larry)
12+
@test data_uri.mediatype == MIME"image/gif"
13+
@test data_uri.isbase64
14+
@test length(data_uri.parameters) == 0
15+
end
16+
17+
@testset "greek_characters" begin
18+
data_uri = DataURI(greek_characters)
19+
@test data_uri.mediatype == MIME"text/plain"
20+
@test !data_uri.isbase64
21+
@test getdata(data_uri) == "%be%fg%be"
22+
@test length(data_uri.parameters) == 1
23+
@test data_uri.parameters[1][1] == "charset"
24+
@test data_uri.parameters[1][2] == "iso-8859-7"
25+
end
26+
27+
@testset "brief_note" begin
28+
data_uri = DataURI(brief_note)
29+
@test data_uri.mediatype == MIME""
30+
@test !data_uri.isbase64
31+
@test getdata(data_uri) == "A%20brief%20note"
32+
@test length(data_uri.parameters) == 0
33+
end
34+
35+
@testset "img_pluto" begin
36+
open("resources/sample_data_uri/img_pluto.txt") do f
37+
content = read(f, String)
38+
data_uri = DataURI(content)
39+
@test data_uri.mediatype == MIME"image/jpeg"
40+
@test data_uri.isbase64
41+
@test length(data_uri.parameters) == 0
42+
end
43+
end
44+
45+
@testset "audio_meow" begin
46+
open("resources/sample_data_uri/audio_meow.txt") do f
47+
content = read(f, String)
48+
data_uri = DataURI(content)
49+
@test data_uri.mediatype == MIME"audio/mpeg"
50+
@test data_uri.isbase64
51+
@test length(data_uri.parameters) == 0
52+
end
53+
end
54+
end
55+
56+
@testset "creating" begin
57+
@testset "larry" begin
58+
data_uri = DataURI(; mediatype=MIME"image/gif", encoded=true, data="R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7")
59+
@test data_uri.uri == larry
60+
end
61+
62+
@testset "greek_characters" begin
63+
data_uri = DataURI(; mediatype=MIME"text/plain", data="%be%fg%be", parameters=["charset" => "iso-8859-7"])
64+
@test data_uri.uri == greek_characters
65+
end
66+
67+
@testset "greek_characters using default mediatype" begin
68+
data_uri = DataURI(; data="%be%fg%be", parameters=["charset" => "iso-8859-7"])
69+
@test data_uri.uri == greek_characters
70+
end
71+
72+
@testset "brief_note" begin
73+
data_uri = DataURI(; mediatype=MIME"", data="A%20brief%20note")
74+
@test data_uri.uri == brief_note
75+
end
76+
end
77+
78+
end

test/resources/sample_data_uri/audio_meow.txt

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

test/resources/sample_data_uri/img_pluto.txt

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ using Test
33

44
include("uri.jl")
55
include("url.jl")
6+
include("data_uri.jl")
67

78
# https://github.com/JuliaWeb/URIs.jl/issues/42
89
struct CustomString <: AbstractString

0 commit comments

Comments
 (0)