format_parser 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab01944664740856d704875f0a74d1b0540379c8e351176e38d3b5bf119e813f
4
- data.tar.gz: b0736ffd074eb3fb49586d52799dd687c72f0a09b6e2d4109b1cbd26a8eac293
3
+ metadata.gz: 5f66a8afff2b85b57587c1cc7914dda25005b024284104bf3b0324b653a3ceff
4
+ data.tar.gz: 7e31d48b97e0dedfe5965b6ae524f1a14bbdc751ac50df11666aee3d4a18e5af
5
5
  SHA512:
6
- metadata.gz: 570e9fcef6a08ad4e800c84d8452d985900f8442d9071477e6cd465b533677f7c39b6ae51c8f94d0ab0e90305ce790c395c3ce54ecda46800921b3311adc23b8
7
- data.tar.gz: 0662cc268f0fc1fc61ac97896811e505f1ae251a2a15fe9027de2414107adb1414b6ce4f3a1111be1215e8e48323330ce8b08b98e521bf7d9ec4a26c8d29f01d
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
@@ -1,3 +1,3 @@
1
1
  module FormatParser
2
- VERSION = '0.11.0'
2
+ VERSION = '0.12.0'
3
3
  end
@@ -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 < StandardError
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 < StandardError
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
@@ -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.11.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-04-30 00:00:00.000000000 Z
12
+ date: 2018-05-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ks