format_parser 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +9 -1
- data/lib/format_parser/version.rb +1 -1
- data/lib/parsers/jpeg_parser.rb +7 -4
- data/lib/remote_io.rb +14 -5
- data/spec/remote_io_spec.rb +21 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f66a8afff2b85b57587c1cc7914dda25005b024284104bf3b0324b653a3ceff
|
4
|
+
data.tar.gz: 7e31d48b97e0dedfe5965b6ae524f1a14bbdc751ac50df11666aee3d4a18e5af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 850a9f04a7006a52016d087c479a5b22048396c55ed51766a8d8c50f4ec66385ad565c3a006687428c762d16fd3aae5aa4f1d250ed1926bde07c0a61387f77d4
|
7
|
+
data.tar.gz: 6afa6ca1706cac48d9ea915bcd0c7ea4900d517eef195880cd0124621c0a7af4a1759ab999ede643dcce8a1066f126f59f030dcc963272c95b130bd397150975
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
## 0.12.0
|
2
|
+
* Relay upstream status from `RemoteIO` in the `status_code` attribute (returns an `Integer`)
|
3
|
+
|
1
4
|
## 0.11.0
|
2
5
|
* Add `Image#display_width_px` and `Image#display_height_px` for EXIF/aspect corrected display dimensions, and provide
|
3
6
|
those values from a few parsers already. Also make full EXIF data available for JPEG/TIFF in `intrinsics[:exif]`
|
data/README.md
CHANGED
@@ -35,7 +35,7 @@ and [dimensions,](https://github.com/sstephenson/dimensions) borrowing from them
|
|
35
35
|
|
36
36
|
## Basic usage
|
37
37
|
|
38
|
-
Pass an IO object that responds to `read` and `seek` to `FormatParser` and the first confirmed match will be returned.
|
38
|
+
Pass an IO object that responds to `read` and `seek` to `FormatParser.parse` and the first confirmed match will be returned.
|
39
39
|
|
40
40
|
```ruby
|
41
41
|
match = FormatParser.parse(File.open("myimage.jpg", "rb"))
|
@@ -46,6 +46,14 @@ match.display_height_px #=> 240
|
|
46
46
|
match.orientation #=> :top_left
|
47
47
|
```
|
48
48
|
|
49
|
+
You can also use `parse_http` passing a URL or `parse_file_at` passing a path:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
match = FormatParser.parse_http('https://upload.wikimedia.org/wikipedia/commons/b/b4/Mardin_1350660_1350692_33_images.jpg')
|
53
|
+
match.nature #=> :image
|
54
|
+
match.format #=> :jpg
|
55
|
+
```
|
56
|
+
|
49
57
|
If you would rather receive all potential results from the gem, call the gem as follows:
|
50
58
|
|
51
59
|
```ruby
|
data/lib/parsers/jpeg_parser.rb
CHANGED
@@ -17,6 +17,7 @@ class FormatParser::JPEGParser
|
|
17
17
|
@buf = FormatParser::IOConstraint.new(io)
|
18
18
|
@width = nil
|
19
19
|
@height = nil
|
20
|
+
@exif_data = nil
|
20
21
|
scan
|
21
22
|
end
|
22
23
|
|
@@ -119,6 +120,7 @@ class FormatParser::JPEGParser
|
|
119
120
|
# the second time around. What we care about, rather, is the EXIF data only. So we will
|
120
121
|
# pry it out of the APP1 frame and parse it as the TIFF segment - which is what EXIFR
|
121
122
|
# does under the hood.
|
123
|
+
marker_length_at = @buf.pos
|
122
124
|
app1_frame_content_length = read_short - 2
|
123
125
|
|
124
126
|
# If there is certainly not enough data in this APP1 to begin with, bail out.
|
@@ -132,10 +134,7 @@ class FormatParser::JPEGParser
|
|
132
134
|
|
133
135
|
# If we could not find the magic Exif\0 string at the start of the marker,
|
134
136
|
# seek to the start of the next marker and return
|
135
|
-
unless maybe_exif_magic_str == EXIF_MAGIC_STRING
|
136
|
-
safe_skip(@buf, app1_frame_content_length - EXIF_MAGIC_STRING.bytesize)
|
137
|
-
return
|
138
|
-
end
|
137
|
+
return unless maybe_exif_magic_str == EXIF_MAGIC_STRING
|
139
138
|
|
140
139
|
# ...and only then read the marker contents and parse it as EXIF
|
141
140
|
exif_data = safe_read(@buf, app1_frame_content_length - EXIF_MAGIC_STRING.bytesize)
|
@@ -146,6 +145,10 @@ class FormatParser::JPEGParser
|
|
146
145
|
rescue EXIFR::MalformedTIFF
|
147
146
|
# Not a JPEG or the Exif headers contain invalid data, or
|
148
147
|
# an APP1 marker was detected in a file that is not a JPEG
|
148
|
+
ensure
|
149
|
+
# Reposition the file pointer to where the next marker will begin,
|
150
|
+
# regardless whether we did find usable EXIF or not
|
151
|
+
@buf.seek(marker_length_at + 2 + app1_frame_content_length)
|
149
152
|
end
|
150
153
|
|
151
154
|
def read_frame
|
data/lib/remote_io.rb
CHANGED
@@ -4,14 +4,23 @@
|
|
4
4
|
# tweaks using `Faraday.default_connection = ...` these will
|
5
5
|
# take effect for these RemoteIO objects as well
|
6
6
|
class FormatParser::RemoteIO
|
7
|
+
class UpstreamError < StandardError
|
8
|
+
# @return Integer
|
9
|
+
attr_reader :status_code
|
10
|
+
def initialize(status_code, message)
|
11
|
+
@status_code = status_code
|
12
|
+
super(message)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
7
16
|
# Represents a failure that might be retried
|
8
17
|
# (like a 5xx response or a timeout)
|
9
|
-
class IntermittentFailure <
|
18
|
+
class IntermittentFailure < UpstreamError
|
10
19
|
end
|
11
20
|
|
12
21
|
# Represents a failure that should not be retried
|
13
22
|
# (like a 4xx response or a DNS resolution error)
|
14
|
-
class InvalidRequest <
|
23
|
+
class InvalidRequest < UpstreamError
|
15
24
|
end
|
16
25
|
|
17
26
|
# @param uri[URI, String] the remote URL to obtain
|
@@ -76,7 +85,7 @@ class FormatParser::RemoteIO
|
|
76
85
|
# Figure out of the server supports content ranges, if it doesn't we have no
|
77
86
|
# business working with that server
|
78
87
|
range_header = response.headers['Content-Range']
|
79
|
-
raise InvalidRequest, "No range support at #{@uri}" unless range_header
|
88
|
+
raise InvalidRequest.new(response.status, "No range support at #{@uri}") unless range_header
|
80
89
|
|
81
90
|
# "Content-Range: bytes 0-0/307404381" is how the response header is structured
|
82
91
|
size = range_header[/\/(\d+)$/, 1].to_i
|
@@ -95,10 +104,10 @@ class FormatParser::RemoteIO
|
|
95
104
|
return
|
96
105
|
when 500..599
|
97
106
|
FormatParser::Measurometer.increment_counter('format_parser.RemoteIO.upstream50x_errors', 1)
|
98
|
-
raise IntermittentFailure, "Server at #{@uri} replied with a #{response.status} and we might want to retry"
|
107
|
+
raise IntermittentFailure.new(response.status, "Server at #{@uri} replied with a #{response.status} and we might want to retry")
|
99
108
|
else
|
100
109
|
FormatParser::Measurometer.increment_counter('format_parser.RemoteIO.invalid_request_errors', 1)
|
101
|
-
raise InvalidRequest, "Server at #{@uri} replied with a #{response.status} and refused our request"
|
110
|
+
raise InvalidRequest.new(response.status, "Server at #{@uri} replied with a #{response.status} and refused our request")
|
102
111
|
end
|
103
112
|
end
|
104
113
|
end
|
data/spec/remote_io_spec.rb
CHANGED
@@ -35,6 +35,27 @@ describe FormatParser::RemoteIO do
|
|
35
35
|
expect { rio.read(100) }.to raise_error(/replied with a 403 and refused/)
|
36
36
|
end
|
37
37
|
|
38
|
+
it 'returns nil on a 416 response' do
|
39
|
+
rio = described_class.new('https://images.invalid/img.jpg')
|
40
|
+
|
41
|
+
fake_resp = double(headers: {}, status: 416, body: 'You stepped off the ledge of the range')
|
42
|
+
expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199').and_return(fake_resp)
|
43
|
+
|
44
|
+
rio.seek(100)
|
45
|
+
expect(rio.read(100)).to be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'sets the status_code of the exception on a 4xx response from upstream' do
|
49
|
+
rio = described_class.new('https://images.invalid/img.jpg')
|
50
|
+
|
51
|
+
fake_resp = double(headers: {}, status: 403, body: 'Please log in')
|
52
|
+
expect(Faraday).to receive(:get).with('https://images.invalid/img.jpg', nil, range: 'bytes=100-199').and_return(fake_resp)
|
53
|
+
|
54
|
+
rio.seek(100)
|
55
|
+
# rubocop: disable Lint/AmbiguousBlockAssociation
|
56
|
+
expect { rio.read(100) }.to raise_error { |e| expect(e.status_code).to eq(403) }
|
57
|
+
end
|
58
|
+
|
38
59
|
it 'returns a nil when the range cannot be satisfied and the response is 416' do
|
39
60
|
rio = described_class.new('https://images.invalid/img.jpg')
|
40
61
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: format_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noah Berman
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-
|
12
|
+
date: 2018-05-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ks
|