Skip to content

Commit

Permalink
DataURI parsing and creation
Browse files Browse the repository at this point in the history
  • Loading branch information
s-celles committed Mar 12, 2024
1 parent dce395c commit 4bd3fe5
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 1 deletion.
3 changes: 3 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
authors = ["Jacob Quinn", "Sam O'Connor", "contributors: https://github.com/JuliaWeb/URIs.jl/graphs/contributors"]
version = "1.5.1"

[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[compat]
julia = "1.6"

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![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)

`URIs` is a Julia package for parsing and working with Uniform Resource
Identifiers, as defined in [RFC 3986](https://www.ietf.org/rfc/rfc3986.txt).
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).

Read the [**stable documentation** on
JuliaHub][docs-stable-url], or see the [development
Expand Down
21 changes: 21 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

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

## Tutorial

### URI
```@meta
DocTestSetup = quote
using URIs
Expand Down Expand Up @@ -48,6 +50,23 @@ Dict{String,String} with 2 entries:
"y" => "hi"
```

### Data URI

```@meta
DocTestSetup = quote
using URIs
end
```

Parsing Data URIs from a string can be done with the [`DataURI`](@ref) constructor:

```jldoctest
julia> u = DataURI("data:,A%20brief%20note")
DataURI("data:,A%20brief%20note")
```

See reference and unit tests for more usage.

## Reference

```@docs
Expand All @@ -61,5 +80,7 @@ escapepath
resolvereference
URIs.splitpath
Base.isvalid(::URI)
DataURI
getdata
```

2 changes: 2 additions & 0 deletions src/URIs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export URI,
queryparams, queryparampairs, absuri, splitfilepath,
escapeuri, unescapeuri, escapepath,
resolvereference
export DataURI, getdata

import Base.==

Expand Down Expand Up @@ -703,6 +704,7 @@ function __init__()
return
end

include("data_uri.jl")
include("deprecate.jl")

end # module
60 changes: 60 additions & 0 deletions src/data_uri.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Base64

const DATA_URI_PATTERNS = [
r"data:(?<mediatype>[^;]+)(?:;(?<parameters>.+))?,(?<data>.+)",
r"data:,(?<data>.+)"
]

"""
DataURI(; mediatype="", encode=false, data="")
DataURI(str) = parse(DataURI, str::String)
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
supported keyword arguments, or from a string.
"""
struct DataURI
uri::String
mediatype::DataType
isbase64::Bool
data::SubString{String}
parameters::Vector{Pair{String, String}}

end

function DataURI(; mediatype=MIME"text/plain", encoded=false, data="", parameters=Pair{String, String}[])
base64 = encoded ? ";base64" : ""
s_parameters = ""
for (key, value) in parameters
s_parameters *= ";$(key)=$(value)"
end
s_mediatype = string(mediatype.parameters[1])
uri = "data:$(s_mediatype)$(s_parameters)$(base64),$(data)"
DataURI(uri, mediatype, encoded, data, parameters)
end

function DataURI(str)
m = match(DATA_URI_PATTERNS[1], str)
if !isnothing(m)
groups = m.captures
mediatype, parameters, data = groups
mime = MIME{Symbol(mediatype)}
isbase64 = endswith(parameters, "base64")
_parameters = filter(p -> p != "base64", split(parameters, ";"))
parameters = Pair{String, String}[]
for p in _parameters
key, value = split(p, "=")
push!(parameters, key => value)
end
else
m = match(DATA_URI_PATTERNS[2], str)
data, = m.captures
mime = MIME""
isbase64 = false
parameters = Pair{String, String}[]
end
DataURI(str, mime, isbase64, data, parameters)
end

function getdata(data_uri::DataURI)
data_uri.isbase64 ? base64decode(data_uri.data) : data_uri.data
end
78 changes: 78 additions & 0 deletions test/data_uri.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using Test

const larry = "data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7"
const greek_characters = "data:text/plain;charset=iso-8859-7,%be%fg%be"
const brief_note = "data:,A%20brief%20note"


@testset "Data URI" begin
@testset "parsing" begin
@testset "larry" begin
data_uri = DataURI(larry)
@test data_uri.mediatype == MIME"image/gif"
@test data_uri.isbase64
@test length(data_uri.parameters) == 0
end

@testset "greek_characters" begin
data_uri = DataURI(greek_characters)
@test data_uri.mediatype == MIME"text/plain"
@test !data_uri.isbase64
@test getdata(data_uri) == "%be%fg%be"
@test length(data_uri.parameters) == 1
@test data_uri.parameters[1][1] == "charset"
@test data_uri.parameters[1][2] == "iso-8859-7"
end

@testset "brief_note" begin
data_uri = DataURI(brief_note)
@test data_uri.mediatype == MIME""
@test !data_uri.isbase64
@test getdata(data_uri) == "A%20brief%20note"
@test length(data_uri.parameters) == 0
end

@testset "img_pluto" begin
open("resources/sample_data_uri/img_pluto.txt") do f
content = read(f, String)
data_uri = DataURI(content)
@test data_uri.mediatype == MIME"image/jpeg"
@test data_uri.isbase64
@test length(data_uri.parameters) == 0
end
end

@testset "audio_meow" begin
open("resources/sample_data_uri/audio_meow.txt") do f
content = read(f, String)
data_uri = DataURI(content)
@test data_uri.mediatype == MIME"audio/mpeg"
@test data_uri.isbase64
@test length(data_uri.parameters) == 0
end
end
end

@testset "creating" begin
@testset "larry" begin
data_uri = DataURI(; mediatype=MIME"image/gif", encoded=true, data="R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7")
@test data_uri.uri == larry
end

@testset "greek_characters" begin
data_uri = DataURI(; mediatype=MIME"text/plain", data="%be%fg%be", parameters=["charset" => "iso-8859-7"])
@test data_uri.uri == greek_characters
end

@testset "greek_characters using default mediatype" begin
data_uri = DataURI(; data="%be%fg%be", parameters=["charset" => "iso-8859-7"])
@test data_uri.uri == greek_characters
end

@testset "brief_note" begin
data_uri = DataURI(; mediatype=MIME"", data="A%20brief%20note")
@test data_uri.uri == brief_note
end
end

end
1 change: 1 addition & 0 deletions test/resources/sample_data_uri/audio_meow.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions test/resources/sample_data_uri/img_pluto.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ using Test

include("uri.jl")
include("url.jl")
include("data_uri.jl")

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

0 comments on commit 4bd3fe5

Please sign in to comment.