Factoring of _Query causes some duplication of effort
_Query and _CanonicalRequest have both ended up with some URL parsing/generation logic in them. There's even an interaction where _Query goes from a structured URL to a string to pass in to _CanonicalRequest which then parses the string to get back to the structured form (_Query._canonical_request).
Also, the generated headers complicate _Query._canonical_request somewhat. The headers must be generated at the time the request is issued (eg so that the date header is recent). This means the headers used to compute the canonical request can't just be a field on _Query. This leads them to be locals in submit where they're not easily accessible to _canonical_request (leading to them being a parameter to that method instead). This complicates the code and makes the tests somewhat messy (which means it's a pain to write tests that exercise particular pieces of the implementation independently - which is particularly appealing for this code since the ultimate output is a cryptographic hash).
Fix this interface so that:
- the code can interact using structured objects to interact.
- _canonical_request can be tested without correctly duplicating the set of headers generated by the implementation and passing them in as an argument.