--[[----------------------------------------------------------------------------

WFHttpClientHeaderParser.lua

--------------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2012 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

----------------------------------------------------------------------------]]--

local function parseHeaderString( headerString )

	local parsed = {}
	local curKey = nil
	local curValue = {}
	
	local function enterCurrentKey()
		if curKey and curValue[ 1 ] then
			local parsedValue = table.concat( curValue )

			if ( curKey == 'Set-Cookie' ) then
				-- add cookie to the array if there's one there, else create a new array of cookies
				local existingCookies = parsed[ curKey ]
				if existingCookies then
					table.insert( existingCookies, parsedValue )
					parsedValue = existingCookies
				else
					parsedValue = { parsedValue }
				end
			end
			
			parsed[ curKey ] = parsedValue
			curValue = {}
			curKey = nil
		end
	end
	
	for row in string.gfind( headerString, "[^\r\n]+" ) do
		-- check for multi-line headers
		if string.find( row, "^ " ) then
			if curKey then
				curValue[ #curValue + 1 ] = row
			end
		else
			enterCurrentKey()
			local _, _, k, v = string.find( row, "([^:]+):[ \t]*(.+)$" )
			curKey = k
			curValue[ 1 ] = v
		end
	end
	enterCurrentKey()
	
	return parsed

end

--------------------------------------------------------------------------------

 -- Apple concatenates the headers together with a comma and we want to split them
 -- apart.

local function FixLameAppleCookieHeader( header )

	local parsedCookies = {}

	-- Here is what we're up against:
	-- MY_COOKIE=BEIE%3Dchtechip; path=/; expires=Fri, 05-Oct-2007 07:41:09 GMT, M_BOKIE=%2C%29_-%3Dsas; path=/through/the/woods; expires=Fri, 05-Oct-2007 07:41:09 GMT

	-- Notice the catch here: The expires field has a comma in it, too!

	local munged = header

	-- Take note of all the expires fields.

	local allExpires = {}
	local index = 0
	for insanity = 1, 200 do
			-- bail if we encounter more than 200 cookies
		index = string.find( munged, "expires=", index+1 )
		if index == nil then
			break
		end
		table.insert( allExpires, index )
	end

	-- Now split on commas, but not if they're too close to the expires field.

	index = 0
	local last = 1
	for insanity = 1, 200 do
			-- bail if we encounter more than 200 fields in this cookie

		local index2
		index, index2 = string.find( munged, ",[ \t]*", index+1 )

		if index == nil then
			local headerValue = string.sub( munged, last )
			table.insert( parsedCookies, headerValue )
			break
		end

		local tooClose = false

		for _, x in ipairs( allExpires ) do

			if index > x and index - x < 13 then

					-- 13 > the length of 'expires=Mdy'
					-- the RFC says the field is MUCH longer, so this
					-- should be fine.	The only thing I wonder is if
					-- some server out there uses an illegal day of the
					-- week token that's more than 3 chars.

				tooClose = true

			end

		end

		if not tooClose then

			local headerValue = string.sub( munged, last, index-1 )
			last = index2+1
			table.insert( parsedCookies, headerValue )

		end

	end

	return parsedCookies

end

--------------------------------------------------------------------------------

local kRawHeaderKey = "< raw : headers >"
local kCookieHeaderKey = "Set-Cookie"

local function standardizeHeaders( headers )

	-- Parse headers on windows which are returned as a single string.

	local rawHeaders = headers and headers[ kRawHeaderKey ]
	if rawHeaders and type( rawHeaders ) == 'string' then

		for k, v in pairs( parseHeaderString( rawHeaders ) ) do
			headers[ k ] = v
		end

		headers[ kRawHeaderKey ] = nil
	end

	-- Parsing for Apple headers which are a table like we want, but have multiple Set-Cookie
	-- headers sent as a single comma-separated string.

	local cookieHeader = headers and headers[ kCookieHeaderKey ]
	if cookieHeader and type( cookieHeader ) == 'string' then

		headers[ kCookieHeaderKey ] = FixLameAppleCookieHeader( cookieHeader )

	end

	return headers

end

--==============================================================================

return {
	parseHeaderString = parseHeaderString,
	standardizeHeaders = standardizeHeaders,
}
