void signRequest(String method) throws IOException, InvalidKeyException, NoSuchAlgorithmException, IllegalStateException {
		StringBuilder buff = new StringBuilder();
		
		buff.append(method).append("\n");
		
		if (headers.containsKey(CONTENT_TYPE_HEADER)) {
			buff.append(headers.get(CONTENT_TYPE_HEADER).toLowerCase());
		}
		// line feed even if no content type header exists (which it will)
		buff.append("\n");
		
		// Range headers..
		if (headers.containsKey(RANGE_HEADER)) {
			buff.append(headers.get(RANGE_HEADER));
		} else if (headers.containsKey(CONTENT_RANGE_HEADER)) {
			buff.append(headers.get(CONTENT_RANGE_HEADER));
		}
		// Even if the range headers were not set, we still need a break
		buff.append("\n");
		
		// if the data header has not been set - we need to do so
		if (!headers.containsKey(DATE_HEADER)) {
			createDateHeader();
		}
		buff.append(headers.get(DATE_HEADER)).append("\n");
		buff.append(URLDecoder.decode(url.getPath(), UTF_8).toLowerCase());
		if (url.getQuery() != null) {
			buff.append("?").append(url.getQuery());
		}
		buff.append("\n");
		
		// 'x-emc' headers must be hashed in alphabetic order and the 
		// values stripped of whitespace
		SortedSet<String> keys = new TreeSet<String>();
		Map<String, String> xEmcHeaders = new HashMap<String, String>();
		
		for (String key : headers.keySet()) {
			if (key.indexOf("x-emc") == 0) {
				String lowerKey = key.toLowerCase();
				keys.add(lowerKey);
				xEmcHeaders.put(lowerKey, headers.get(key).replace("\n", ""));
			}
		}
		int initial = buff.length();
		for (String key : keys) {
			if (buff.length() > initial) {
				buff.append("\n");
			}
			buff.append(key).append(':').append(normalizeSpace(xEmcHeaders.get(key)));
		}
		
		String hash = signHash(buff.toString());
		
		headers.put(X_EMC_SIGNATURE_HEADER, hash);
	}