client has 'h' flag in "*cap" info string format of svc_download message: ([url (string)] [newname (string)] | [data]) size and percent are always present. url is present only for http redirects. data is present only when size is > 0 (ie, normal downloading) newname is present for all http redirects (but may be the empty string) or if the file to download has a different name to what what requested. This is so the client saves the downloaded file with the correct name (in QF, this is currently used for gzipped transfers, but there are plans to enable whole pak downloads (similar to RTCW and ET)). size is the number of data bytes in the message (if >= 0) or a special flag: -1 file not found. download aborted -2 download filename is not what was requested (in QF, this is because the file has been gzipped and has the .gz extension). In this case, newname is in the message. Currently, QF checks newname to ensure the only modification is the addition of an extension. -3 http redirect. url is always present and is the full url to download. If the download name is the same as the requested name, newname will be the empty string (""), otherwise it contains the new name of the file. See -2. QF #defines for the above values: #define DL_NOFILE -1 #define DL_RENAME -2 #define DL_HTTP -3 Pseudo-code representing client side handling of svc_download ======== CL_ParseDownload { size = MSG_ReadShort (net_message); percent = MSG_ReadByte (net_message); if (size == DL_NOFILE) { abort download return } if (size == DL_RENAME) { newname = MSG_ReadString (net_message); if (newname is bad) { abort download return } rename file return } if (size == DL_HTTP) { url = MSG_ReadString (net_message); newname = MSG_ReadString (net_message); if (newname != "") { if (newname is bad) { abort download return } rename file } start http transfer return } normal download processing } ======== NOTES: While the QF quakeworld server simply appends the requested file's path to the given url base, with the addition of a '/' (eg, "maps/foo.map" to "http://server/downloads", giving "http://server/downloads/maps/foo.map"), so long as it is reasonable for the client to not rename the download file, there is no requirement for the full url to match the requested name in any manner, and newname can be left as empty (""). However, if the client must rename the file, set newname to the new name. The extension checking is done as a security measure. Currently, the only reason QF renames a download is if it found eg "maps/foo.map.gz" instead of "maps/foo.map" (2:1 to 3:1 compression on maps is nice). This is the basis of the extension checking the QF clients do. TODO: [this has no bearing on the protocol itself] One good reason for the name being quite different is when the requested file is part of a pak file (and downloading the pak file is permitted), the entire pak file can be sent instead. QF does not yet do this, but it should be easy enough to implement: if file_from_pak (from FOpenFile) is set, and pak file downloading is permitted, do a rename (-2 for non-http, set newname in http) and send that instead. The client can check for a ".pak" extension in the rename, permit it, and then cause a rescan of the game directory in order to pick up the new pak file.