mirror of https://github.com/OpenVPN/openvpn-gui
During import from url take filename from content-disposition
If the http header "Content-Disposition:" is present take the filename specified in there as the name of the imported profile, falling back to scanning the file contents for metadata. If both filename= and filename*= attributes are present, the latter takes precedence provided the character set is utf-8. (Extended attributes as defined in RFC 5987). In case of import from AS, the behaviour is unchanaged. Issue: #450. Signed-off-by: Selva Nair <selva.nair@gmail.com>pull/464/head
parent
859d0fbf2f
commit
77e32fa676
101
as.c
101
as.c
|
@ -22,6 +22,7 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <wininet.h>
|
#include <wininet.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "localization.h"
|
#include "localization.h"
|
||||||
|
@ -38,6 +39,21 @@
|
||||||
#define PROFILE_NAME_TOKEN L"# OVPN_ACCESS_SERVER_PROFILE="
|
#define PROFILE_NAME_TOKEN L"# OVPN_ACCESS_SERVER_PROFILE="
|
||||||
#define FRIENDLY_NAME_TOKEN L"# OVPN_ACCESS_SERVER_FRIENDLY_NAME="
|
#define FRIENDLY_NAME_TOKEN L"# OVPN_ACCESS_SERVER_FRIENDLY_NAME="
|
||||||
|
|
||||||
|
/** Replace characters not allowed in Windows filenames with '_' */
|
||||||
|
void
|
||||||
|
SanitizeFilename(wchar_t *fname)
|
||||||
|
{
|
||||||
|
const wchar_t *reserved = L"<>:\"/\\|?*;"; /* remap these and ascii 1 to 31 */
|
||||||
|
while (*fname) {
|
||||||
|
wchar_t c = *fname;
|
||||||
|
if (c < 32 || wcschr(reserved, c))
|
||||||
|
{
|
||||||
|
*fname = L'_';
|
||||||
|
}
|
||||||
|
++fname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract profile name from profile content.
|
* Extract profile name from profile content.
|
||||||
*
|
*
|
||||||
|
@ -87,14 +103,7 @@ ExtractProfileName(const WCHAR *profile, const WCHAR *default_name, WCHAR *out_n
|
||||||
|
|
||||||
out_name[out_name_length - 1] = L'\0';
|
out_name[out_name_length - 1] = L'\0';
|
||||||
|
|
||||||
/* sanitize profile name */
|
SanitizeFilename(out_name);
|
||||||
const WCHAR *reserved = L"<>:\"/\\|?*;"; /* remap these and ascii 1 to 31 */
|
|
||||||
while (*out_name) {
|
|
||||||
wchar_t c = *out_name;
|
|
||||||
if (c < 32 || wcschr(reserved, c))
|
|
||||||
*out_name = L'_';
|
|
||||||
++out_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
@ -295,6 +304,77 @@ GetASUrl(const WCHAR *host, bool autologin, struct UrlComponents *comps)
|
||||||
comps->path[URL_LEN - 1] = L'\0';
|
comps->path[URL_LEN - 1] = L'\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read content-disposition header and extract file name if any.
|
||||||
|
* Returns true on success, false otherwise.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
ExtractFilenameFromHeader(HINTERNET hRequest, wchar_t *name, size_t len)
|
||||||
|
{
|
||||||
|
DWORD index = 0;
|
||||||
|
char *buf = NULL;
|
||||||
|
DWORD buflen = 256;
|
||||||
|
bool res = false;
|
||||||
|
UINT codepage = 28591; /* ISO 8859_1 -- the default char set for http header */
|
||||||
|
|
||||||
|
buf = malloc(buflen);
|
||||||
|
if (!buf
|
||||||
|
|| (!HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_DISPOSITION, buf, &buflen, &index)
|
||||||
|
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER))
|
||||||
|
{
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||||
|
{
|
||||||
|
/* try again with more space */
|
||||||
|
free(buf);
|
||||||
|
buf = malloc(buflen);
|
||||||
|
if (!buf
|
||||||
|
|| !HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_DISPOSITION, buf, &buflen, &index))
|
||||||
|
{
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look for filename=<name> */
|
||||||
|
char *p = strtok(buf, ";");
|
||||||
|
char *fn = NULL;
|
||||||
|
for ( ; p; p = strtok(NULL, ";"))
|
||||||
|
{
|
||||||
|
if ((fn = strstr(p, "filename=")) != NULL)
|
||||||
|
{
|
||||||
|
fn += 9;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if ((fn = strstr(p, "filename*=utf-8''")) != NULL)
|
||||||
|
{
|
||||||
|
fn += 17;
|
||||||
|
UrlUnescapeA(fn, NULL, NULL, URL_UNESCAPE_INPLACE);
|
||||||
|
codepage = CP_UTF8;
|
||||||
|
break; /* we prefer filename*= value */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fn && strlen(fn))
|
||||||
|
{
|
||||||
|
StrTrimA(fn, " \""); /* strip leading and trailing spaces and quotes */
|
||||||
|
wchar_t *wfn = WidenEx(codepage, fn);
|
||||||
|
if (wfn)
|
||||||
|
{
|
||||||
|
wcsncpy_s(name, len, wfn, _TRUNCATE);
|
||||||
|
res = true;
|
||||||
|
free(wfn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SanitizeFilename(name);
|
||||||
|
|
||||||
|
done:
|
||||||
|
free(buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download profile from a generic URL and save it to a temp file
|
* Download profile from a generic URL and save it to a temp file
|
||||||
*
|
*
|
||||||
|
@ -467,6 +547,10 @@ again:
|
||||||
}
|
}
|
||||||
|
|
||||||
WCHAR name[MAX_PATH] = {0};
|
WCHAR name[MAX_PATH] = {0};
|
||||||
|
/* read filename from header or from the profile metadata */
|
||||||
|
if (strlen(comps->content_type) == 0 /* AS profile */
|
||||||
|
|| !ExtractFilenameFromHeader(hRequest, name, MAX_PATH))
|
||||||
|
{
|
||||||
WCHAR* wbuf = Widen(buf);
|
WCHAR* wbuf = Widen(buf);
|
||||||
if (!wbuf) {
|
if (!wbuf) {
|
||||||
MessageBoxW(hWnd, L"Failed to convert profile content to wchar", _T(PACKAGE_NAME), MB_OK);
|
MessageBoxW(hWnd, L"Failed to convert profile content to wchar", _T(PACKAGE_NAME), MB_OK);
|
||||||
|
@ -474,6 +558,7 @@ again:
|
||||||
}
|
}
|
||||||
ExtractProfileName(wbuf, comps->host, name, MAX_PATH);
|
ExtractProfileName(wbuf, comps->host, name, MAX_PATH);
|
||||||
free(wbuf);
|
free(wbuf);
|
||||||
|
}
|
||||||
|
|
||||||
/* save profile content into tmp file */
|
/* save profile content into tmp file */
|
||||||
DWORD res = GetTempPathW((DWORD)out_path_size, out_path);
|
DWORD res = GetTempPathW((DWORD)out_path_size, out_path);
|
||||||
|
|
22
misc.c
22
misc.c
|
@ -466,22 +466,23 @@ CheckFileAccess (const TCHAR *path, int access)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Convert a NUL terminated utf8 string to widechar. The caller must free
|
* Convert a NUL terminated narrow string to wide string using
|
||||||
|
* specified codepage. The caller must free
|
||||||
* the returned pointer. Return NULL on error.
|
* the returned pointer. Return NULL on error.
|
||||||
*/
|
*/
|
||||||
WCHAR *
|
WCHAR *
|
||||||
Widen(const char *utf8)
|
WidenEx(UINT codepage, const char *str)
|
||||||
{
|
{
|
||||||
WCHAR *wstr = NULL;
|
WCHAR *wstr = NULL;
|
||||||
if (!utf8)
|
if (!str)
|
||||||
return wstr;
|
return wstr;
|
||||||
|
|
||||||
int nch = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
|
int nch = MultiByteToWideChar(codepage, 0, str, -1, NULL, 0);
|
||||||
if (nch > 0)
|
if (nch > 0)
|
||||||
wstr = malloc(sizeof(WCHAR) * nch);
|
wstr = malloc(sizeof(WCHAR) * nch);
|
||||||
if (wstr)
|
if (wstr)
|
||||||
nch = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, nch);
|
nch = MultiByteToWideChar(codepage, 0, str, -1, wstr, nch);
|
||||||
|
|
||||||
if (nch == 0 && wstr)
|
if (nch == 0 && wstr)
|
||||||
{
|
{
|
||||||
|
@ -492,6 +493,15 @@ Widen(const char *utf8)
|
||||||
return wstr;
|
return wstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Same as WidenEx with codepage = UTF8
|
||||||
|
*/
|
||||||
|
WCHAR *
|
||||||
|
Widen(const char *utf8)
|
||||||
|
{
|
||||||
|
return WidenEx(CP_UTF8, utf8);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return false if input contains any characters in exclude */
|
/* Return false if input contains any characters in exclude */
|
||||||
BOOL
|
BOOL
|
||||||
validate_input(const WCHAR *input, const WCHAR *exclude)
|
validate_input(const WCHAR *input, const WCHAR *exclude)
|
||||||
|
|
1
misc.h
1
misc.h
|
@ -46,6 +46,7 @@ BOOL CheckFileAccess (const TCHAR *path, int access);
|
||||||
BOOL Base64Encode(const char *input, int input_len, char **output);
|
BOOL Base64Encode(const char *input, int input_len, char **output);
|
||||||
int Base64Decode(const char *input, char **output);
|
int Base64Decode(const char *input, char **output);
|
||||||
WCHAR *Widen(const char *utf8);
|
WCHAR *Widen(const char *utf8);
|
||||||
|
WCHAR *WidenEx(UINT codepage, const char *utf8);
|
||||||
BOOL validate_input(const WCHAR *input, const WCHAR *exclude);
|
BOOL validate_input(const WCHAR *input, const WCHAR *exclude);
|
||||||
/* Concatenate two wide strings with a separator */
|
/* Concatenate two wide strings with a separator */
|
||||||
void wcs_concat2(WCHAR *dest, int len, const WCHAR *src1, const WCHAR *src2, const WCHAR *sep);
|
void wcs_concat2(WCHAR *dest, int len, const WCHAR *src1, const WCHAR *src2, const WCHAR *sep);
|
||||||
|
|
Loading…
Reference in New Issue