Compare commits
39 Commits
release-1.
...
branch-1.6
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bc335f5df7 | ||
![]() |
cf31814e55 | ||
![]() |
3b0fd070fd | ||
![]() |
9f69fb1b80 | ||
![]() |
c124ae6507 | ||
![]() |
51a01cdba1 | ||
![]() |
6905714a7e | ||
![]() |
72460df747 | ||
![]() |
a596abfbe3 | ||
![]() |
fbbb24f406 | ||
![]() |
0508fb0d6e | ||
![]() |
848d66e69d | ||
![]() |
04fb684323 | ||
![]() |
faaef39a3c | ||
![]() |
a1193f385e | ||
![]() |
c20f2bd3a1 | ||
![]() |
3fc0f9ad1d | ||
![]() |
2211cc14e6 | ||
![]() |
bf60dc06e0 | ||
![]() |
908785fba7 | ||
![]() |
1a28e8ff51 | ||
![]() |
89ad5e6779 | ||
![]() |
062ac0c926 | ||
![]() |
06aa3b17c4 | ||
![]() |
9f444a680e | ||
![]() |
8e3a71905b | ||
![]() |
72c29ef1f6 | ||
![]() |
f6a3102b48 | ||
![]() |
9a9c4e829e | ||
![]() |
7a571f513e | ||
![]() |
f10730f616 | ||
![]() |
c70f5ce323 | ||
![]() |
a3c540bc9b | ||
![]() |
7b1aa4c9e3 | ||
![]() |
907c7c2621 | ||
![]() |
25c27b8af7 | ||
![]() |
dcbbc30f5c | ||
![]() |
3509991872 | ||
![]() |
6279b7fa5f |
10
.gitignore
vendored
10
.gitignore
vendored
@@ -73,6 +73,14 @@ GRTAGS
|
||||
GSYMS
|
||||
GTAGS
|
||||
|
||||
# QT-Creator files
|
||||
Makefile.am.user
|
||||
pupnp.config
|
||||
pupnp.creator
|
||||
pupnp.creator.user
|
||||
pupnp.files
|
||||
pupnp.includes
|
||||
|
||||
*.orig
|
||||
*~
|
||||
\#*#
|
||||
@@ -109,4 +117,4 @@ docs/doxygen
|
||||
/build/vc10/out.vc9.Win32/Debug
|
||||
/build/vc10/out.vc10.Win32
|
||||
/build/vc10/out.vc10.x64
|
||||
/pthreads
|
||||
/pthreads
|
||||
|
278
ChangeLog
278
ChangeLog
@@ -1,3 +1,281 @@
|
||||
*******************************************************************************
|
||||
Version 1.6.20
|
||||
*******************************************************************************
|
||||
|
||||
2015-02-04 Shaun Marko <semarko@users.sf.net>
|
||||
|
||||
Bug tracker #124 Build fails with --enable-debug
|
||||
|
||||
Build environment
|
||||
Fedora 21
|
||||
X86-64
|
||||
* gcc 4.9.2
|
||||
|
||||
How to repeat
|
||||
$ ./configure --enable debug
|
||||
$ make
|
||||
libtool: compile: gcc -DHAVE_CONFIG_H -I. -I.. -I../upnp/inc -I./inc -I../threadutil/inc
|
||||
-I../ixml/inc -I./src/inc -pthread -g -O2 -Wall -MT src/api/libupnp_la-UpnpString.lo
|
||||
-MD -MP -MF src/api/.deps/libupnp_la-UpnpString.Tpo -c src/api/UpnpString.c
|
||||
-fPIC -DPIC -o src/api .libs/libupnp_la-UpnpString.o src/api/UpnpString.c:47:16:
|
||||
error: expected identifier or '(' before 'extension'
|
||||
extern char *strndup(const char *string, size_t __n);
|
||||
^
|
||||
Makefile:1016: recipe for target 'src/api/libupnp_la-UpnpString.lo' failed
|
||||
|
||||
Reason for failure
|
||||
Build enables -O2 optimization flags which causes the inclusion of a
|
||||
macro implementation of strndup from include/bits/string2.h.
|
||||
|
||||
Workarounds
|
||||
Disable optimization when configuring or making:
|
||||
$ configure CFLAGS='-g -pthread -O0' --enable-debug
|
||||
$ make
|
||||
or
|
||||
$ configure --enable-debug
|
||||
$ make CFLAGS='-g -pthread -O0' Define NO_STRING_INLINES
|
||||
$ export CFLAGS="-DNO_STRING_INLINES -O2"
|
||||
$ ./configure --enagble-debug
|
||||
$ make
|
||||
|
||||
Fix
|
||||
* Don't declare strndup in src/api/UpnpString.c if it exists
|
||||
|
||||
2015-02-01 Jean-Francois Dockes <medoc@users.sf.net>
|
||||
|
||||
Out-of-tree builds seem to be currently broken, because ixml and
|
||||
threadutil files need an include path to include UpnpGlobal.h, and
|
||||
configure tries to copy files into a directory which it does not create.
|
||||
The patch fixes both issues.
|
||||
|
||||
2014-01-03 Peng <howtofly(at)gmail.com>
|
||||
|
||||
rewrite soap_device.c
|
||||
|
||||
1) separate HTTP handling from SOAP handling
|
||||
2) remove repeated validity check, each check is performed exactly once
|
||||
3) fix HTTP status code per UPnP spec, SOAP spec and RFC 2774
|
||||
|
||||
*******************************************************************************
|
||||
Version 1.6.19
|
||||
*******************************************************************************
|
||||
|
||||
2013-11-14 Marcelo Roberto Jimenez <mroberto(at)users.sourceforge.net>
|
||||
|
||||
SF Bug Tracker #119, Creator: Klaus Fischer
|
||||
Access violation due to changed usage of pthreads-win32
|
||||
|
||||
Dear libupnp developers,
|
||||
|
||||
I have experienced a crash (access violation) when using libupnp on
|
||||
Windows. The crash is actually located in pthreads-win32 and happens
|
||||
when repeatedly de-/initializing libupnp on Win32 in the same process
|
||||
and both libupnp and pthreads-win32 are compiled as static libraries.
|
||||
|
||||
So I'm doing this:
|
||||
- UpnpInit()
|
||||
- UpnpFinish()
|
||||
- UpnpInit() <- Crash
|
||||
|
||||
I am already in touch with Ross Johnson on the pthreads-win32 mailing
|
||||
list regarding this issue:
|
||||
|
||||
http://sourceware.org/ml/pthreads-win32/2013/msg00020.html
|
||||
|
||||
He told me the problem is that the functions
|
||||
pthread_win32_process_attach/detach_np() should no longer be called
|
||||
directly, but are invoked automatically now since version 2.9.0 of
|
||||
pthreads-win32, which has been released approx. 1.5 years ago. Please
|
||||
refer to above link for in-depth information.
|
||||
|
||||
So for proper using of latest pthreads-win32 library, those function
|
||||
calls should vanish inside libupnp. Could you consider adapting libupnp
|
||||
in that way? I would really like to use both libraries out-of-the-box
|
||||
without local modifications, and this issue prevents that.
|
||||
|
||||
Best regards,
|
||||
Klaus
|
||||
|
||||
2013-11-08 Peng <howtofly(at)gmail.com>
|
||||
|
||||
Fix several minor bugs in soap_device.c
|
||||
|
||||
1) remove redundant free
|
||||
2) avoid user-provided ErrStr being overwritten by the default one
|
||||
3) eliminated memory leak possiblity in handle_query_variable
|
||||
|
||||
2013-11-08 Peng <howtofly(at)gmail.com>
|
||||
|
||||
Fix return value check of parse_uri.
|
||||
|
||||
2012-06-19 Yoichi NAKAYAMA <yoichi.nakayama(at)gmail.com>
|
||||
|
||||
SF Bug Tracker #118, Creator: T.Iwamoto
|
||||
tv_ctrlpt crashes after detecting a later version of tvcontrol service
|
||||
|
||||
From: gon3456@users.sf.net
|
||||
Steps to reproduce:
|
||||
1. Extracts and build libupnp-1.6.18
|
||||
$ tar -xjf /path/to/archive/libupnp-1.6.18.tar.bz2
|
||||
$ cd libupnp-1.6.18
|
||||
$ ./configure
|
||||
$ make
|
||||
2. Applies the attached patch and remake.
|
||||
$ patch -p1 < /path/to/patch/libupnp-1.6.18.patch
|
||||
$ make
|
||||
3. Run tv_device.
|
||||
$ cd upnp/sample
|
||||
$ ./tv_device
|
||||
4. Run tv_ctrlpt; the tv_ctrlpt crashes soon.
|
||||
$ ./tv_ctrlpt
|
||||
Segmentation fault (core dumped)
|
||||
This is an issue report about the sample program of control point.
|
||||
The tv_ctrlpt crashes after detecting a tvdevice that contains tvcontrol:2 or higher version of tvcontrol service.
|
||||
tv_ctrlpt should detect correctly such devices due to forward compatibility of control points with device.
|
||||
For more information about the compatibility, please refer the following document:
|
||||
DLNA Architectures and Protocols Part 1 2011 December - 7.3.2.1.3 (GUN:GZJXU)
|
||||
The attached patch changes the sample programs as below:
|
||||
- device: changes version of tvcontrol service from 1 to 2. This change may occur in the future.
|
||||
- cp: nothing changed: cp knows version 1 of tvcontrol service only.
|
||||
I know many vendors implements their control points based on the tv_ctrlpt, so I hope to fix this issue ASAP.
|
||||
|
||||
==
|
||||
|
||||
From: Yoichi NAKAYAMA
|
||||
SEGV is caused by strcpy with NULL argument.
|
||||
Attached patch will avoid SEGV in strcpy, but there may be other inconsistencies.
|
||||
|
||||
> I know many vendors implements their control points based on the tv_ctrlpt,
|
||||
|
||||
I don't think so. I think tv_ctrlpt is just a sample to be used with tv_device.
|
||||
|
||||
2013-10-28 Pino Toscano <pinotree(at)users.sourceforge.net>
|
||||
|
||||
Fix compilation on GNU/Hurd
|
||||
|
||||
2013-10-28 Peng <howtofly(at)gmail.com>
|
||||
|
||||
Fix return value of http_RecvPostMessage and update httpparser.c's comments
|
||||
|
||||
2013-10-17 Peng <howtofly(at)gmail.com>
|
||||
|
||||
Fix return value of process_request and related subroutines
|
||||
1) Only HTTP_XXX should be return
|
||||
2) Make default return value work for process_request
|
||||
|
||||
2013-10-15 Peng <howtofly(at)gmail.com>
|
||||
|
||||
Fix Content-Range generation bug
|
||||
|
||||
2013-09-10 zexian chen <chenzexian88(at)gmail.com>
|
||||
|
||||
Hi,
|
||||
|
||||
I had found some bugs about memory leak on libupnp-1.6.18.
|
||||
|
||||
It may lead to memory leak when calling ThreadPoolAdd() or
|
||||
ThreadPoolAddPersistent() which does not return 0.
|
||||
|
||||
See the attachment for patch.
|
||||
|
||||
2013-09-03 Peng <howtofly(at)gmail.com>
|
||||
|
||||
Fix return value of config_description_doc.
|
||||
|
||||
UPNP_E_XXX should not be used instead of IXML_XXX
|
||||
|
||||
2013-09-03 Peng <howtofly(at)gmail.com>
|
||||
|
||||
Remove faulty free in GetDescDocumentAndURL.
|
||||
|
||||
temp_str, which points to part of description, should not be freed.
|
||||
|
||||
2013-09-02 Peng <howtofly(at)gmail.com>
|
||||
|
||||
Suppose the UPnP device is listening on 192.168.1.102:49152. Use the following to send
|
||||
garbage bytes to the device:
|
||||
while true; do echo "\""; done | netcat 192.168.1.102 49152
|
||||
|
||||
The device just keeps receiving these bytes and its memory usage keeps growing.
|
||||
Malicious client may exploit it to exhaust the device's memory.
|
||||
|
||||
The attached patch eliminates this possibility.
|
||||
|
||||
2013-09-02 Peng <howtofly(at)gmail.com>
|
||||
|
||||
1) restore the scanner's original cursor position in case of
|
||||
insufficient input;
|
||||
2) free the memories allocated for a new header in case of a failure.
|
||||
|
||||
2013-08-13 Peng <howtofly(at)gmail.com>
|
||||
|
||||
Patch to fix behaviou when char is signed
|
||||
|
||||
it seems to me that there is still something wrong:
|
||||
|
||||
1) the new is_qdtext_char() is incorrect.
|
||||
There is a trap if char is implemented as signed char.
|
||||
Suppose that c is '\xFF', it will be -1 when converted to an int.
|
||||
By definition, c should be qdtext:
|
||||
qdtext = <any TEXT except <">>
|
||||
TEXT = <any OCTET except CTLs, but including LWS>
|
||||
OCTET = <any 8-bit sequence of data>
|
||||
|
||||
2) the character after '\\' could be either part of a quoted-pair
|
||||
(together with '\\'), or a normal qdtext, since '\\' itself can
|
||||
be treated as a qdtext. This is equivalent to saying that the
|
||||
character after '\\' in a quoted string could be ANY octet.
|
||||
|
||||
A patch based on the above two observations is attached.
|
||||
|
||||
Peng
|
||||
|
||||
2013-08-13 Marcelo Roberto Jimenez <mroberto(at)users.sourceforge.net>
|
||||
|
||||
Enforce RFC 2616 and accept "0" after a backslash for quoted-strings.
|
||||
|
||||
Reported by Peng <howtofly(at)gmail.com>
|
||||
|
||||
2013-08-13 Peng <howtofly(at)gmail.com>
|
||||
|
||||
Patch to make scanner_get_token more robust (avoid over-reading).
|
||||
|
||||
2013-07-30 Zheng Peng <darkelf2010(at)users.sf.net>
|
||||
|
||||
SF ticket #116 UpnpRemoveVirtualDir wrong linked list operation
|
||||
|
||||
What if pVirtualDirList has two nodes and what we want to delete is the
|
||||
first one. Patch attached.
|
||||
|
||||
2013-07-30 Sebastian Brandt <s.brandt(at)aixtrusion.de>
|
||||
|
||||
Dear libupnp-devels,
|
||||
when POST'ing to the simple web server in libupnp, the application crashes.
|
||||
This is caused by a missing "..." argument in webserver.c:1533.
|
||||
Seems it has been there for a long time ... 1.6.9 and 1.6.18 have it.
|
||||
|
||||
webserver.c:1533 calls http_MakeMessage
|
||||
/* Send response. */
|
||||
http_MakeMessage(&headers, 1, 1,
|
||||
"RTLSXcCc",
|
||||
ret, "text/html", X_USER_AGENT);
|
||||
The format parameter RTLSXcCc needs four arguments -
|
||||
R - response code - ret,
|
||||
T- content type - text/html,
|
||||
L - struct SendInstruction * - NOT PRESENT
|
||||
X - user agent - X_USER_AGENT
|
||||
|
||||
This results in a crash.
|
||||
|
||||
Changing to
|
||||
http_MakeMessage(&headers, 1, 1,
|
||||
"RTLSXcCc",
|
||||
ret, "text/html", &RespInstr, X_USER_AGENT);
|
||||
solves the situation.
|
||||
|
||||
Yours,
|
||||
Sebastian Brandt
|
||||
|
||||
*******************************************************************************
|
||||
Version 1.6.18
|
||||
*******************************************************************************
|
||||
|
2
Doxyfile
2
Doxyfile
@@ -31,7 +31,7 @@ PROJECT_NAME = libUPnP
|
||||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER = 1.6.18
|
||||
PROJECT_NUMBER = 1.6.20
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
|
10
THANKS
10
THANKS
@@ -23,6 +23,7 @@ exempt of errors.
|
||||
- Craig Nelson
|
||||
- David Blanchet
|
||||
- David Maass
|
||||
- Dirk (dirk_vdb)
|
||||
- Emil Ljungdahl
|
||||
- Erik Johansson
|
||||
- Eric Tanguy
|
||||
@@ -37,6 +38,7 @@ exempt of errors.
|
||||
- Ingo Hofmann
|
||||
- Ivan Romanov (ivanromanov)
|
||||
- Jiri Zouhar
|
||||
- Jean-Francois Dockes (medoc)
|
||||
- John Dennis
|
||||
- Jonathan Casiot (no_dice)
|
||||
- Josh Carroll
|
||||
@@ -54,10 +56,16 @@ exempt of errors.
|
||||
- Oskar Liljeblad
|
||||
- Michael (oxygenic)
|
||||
- Paul Vixie
|
||||
- Peng
|
||||
- Peter Hartley
|
||||
- Philipp Matthias Hahn
|
||||
- Pino Toscano (pinotree)
|
||||
- Rene Hexel
|
||||
- Robert Buckley (rbuckley)
|
||||
- Robert Gingher (robsbox)
|
||||
- Ronan Menard
|
||||
- Sebastian Brandt
|
||||
- Shaun Marko (semarko)
|
||||
- Siva Chandran
|
||||
- Stefan Sommerfeld (zerocom)
|
||||
- Stéphane Corthésy
|
||||
@@ -68,4 +76,6 @@ exempt of errors.
|
||||
- Tom (tomdev2)
|
||||
- Yoichi Nakayama (yoichi)
|
||||
- zephyrus (zephyrus00jp)
|
||||
- zexian chen
|
||||
- Zheng Peng (darkelf2010)
|
||||
|
||||
|
@@ -105,7 +105,7 @@
|
||||
#define PACKAGE_NAME "libupnp"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "libupnp 1.6.18"
|
||||
#define PACKAGE_STRING "libupnp 1.6.20"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "libupnp"
|
||||
@@ -114,7 +114,7 @@
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.6.18"
|
||||
#define PACKAGE_VERSION "1.6.20"
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
@@ -172,13 +172,13 @@
|
||||
#define UPNP_VERSION_MINOR 6
|
||||
|
||||
/* see upnpconfig.h */
|
||||
#define UPNP_VERSION_PATCH 18
|
||||
#define UPNP_VERSION_PATCH 20
|
||||
|
||||
/* see upnpconfig.h */
|
||||
#define UPNP_VERSION_STRING "1.6.18"
|
||||
#define UPNP_VERSION_STRING "1.6.20"
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "1.6.18"
|
||||
#define VERSION "1.6.20"
|
||||
|
||||
/* File Offset size */
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
@@ -40,7 +40,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
/** The library version (string) e.g. "1.3.0" */
|
||||
#define UPNP_VERSION_STRING "1.6.18"
|
||||
#define UPNP_VERSION_STRING "1.6.20"
|
||||
|
||||
/** Major version of the library */
|
||||
#define UPNP_VERSION_MAJOR 1
|
||||
@@ -49,7 +49,7 @@
|
||||
#define UPNP_VERSION_MINOR 6
|
||||
|
||||
/** Patch version of the library */
|
||||
#define UPNP_VERSION_PATCH 18
|
||||
#define UPNP_VERSION_PATCH 20
|
||||
|
||||
/** The library version (numeric) e.g. 10300 means version 1.3.0 */
|
||||
#define UPNP_VERSION \
|
||||
|
31
configure.ac
31
configure.ac
@@ -9,7 +9,7 @@
|
||||
|
||||
AC_PREREQ(2.60)
|
||||
|
||||
AC_INIT([libupnp], [1.6.18], [mroberto@users.sourceforge.net])
|
||||
AC_INIT([libupnp], [1.6.20], [mroberto@users.sourceforge.net])
|
||||
dnl ############################################################################
|
||||
dnl # *Independently* of the above libupnp package version, the libtool version
|
||||
dnl # of the 3 libraries need to be updated whenever there is a change released:
|
||||
@@ -328,9 +328,32 @@ dnl #AC_SUBST([LT_VERSION_THREADUTIL], [6:3:0])
|
||||
dnl #AC_SUBST([LT_VERSION_UPNP], [9:2:3])
|
||||
dnl #
|
||||
dnl ############################################################################
|
||||
dnl # Release 1.6.19:
|
||||
dnl # "current:revision:age"
|
||||
dnl #
|
||||
dnl # - Code has changed in threadutil
|
||||
dnl # revision: 3 -> 4
|
||||
dnl # - Code has changed in upnp
|
||||
dnl # revision: 2 -> 3
|
||||
dnl #
|
||||
dnl #AC_SUBST([LT_VERSION_IXML], [2:8:0])
|
||||
dnl #AC_SUBST([LT_VERSION_THREADUTIL], [6:4:0])
|
||||
dnl #AC_SUBST([LT_VERSION_UPNP], [9:3:3])
|
||||
dnl #
|
||||
dnl ############################################################################
|
||||
dnl # Release 1.6.20:
|
||||
dnl # "current:revision:age"
|
||||
dnl #
|
||||
dnl # -
|
||||
dnl #
|
||||
dnl #AC_SUBST([LT_VERSION_IXML], [::])
|
||||
dnl #AC_SUBST([LT_VERSION_THREADUTIL], [::])
|
||||
dnl #AC_SUBST([LT_VERSION_UPNP], [::])
|
||||
dnl #
|
||||
dnl ############################################################################
|
||||
AC_SUBST([LT_VERSION_IXML], [2:8:0])
|
||||
AC_SUBST([LT_VERSION_THREADUTIL], [6:3:0])
|
||||
AC_SUBST([LT_VERSION_UPNP], [9:2:3])
|
||||
AC_SUBST([LT_VERSION_THREADUTIL], [6:4:0])
|
||||
AC_SUBST([LT_VERSION_UPNP], [9:3:3])
|
||||
dnl ############################################################################
|
||||
dnl # Repeating the algorithm to place it closer to the modificatin place:
|
||||
dnl # - library code modified: revision++
|
||||
@@ -508,6 +531,7 @@ AC_MSG_RESULT($docdir)
|
||||
#
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_MAKE_SET
|
||||
@@ -701,6 +725,7 @@ AC_OUTPUT
|
||||
# Files copied for windows compilation.
|
||||
#
|
||||
echo "configure: copying \"autoconfig.h\" to \"build/inc/autoconfig.h\""
|
||||
test -d build/inc || mkdir -p build/inc
|
||||
cp autoconfig.h build/inc/autoconfig.h
|
||||
echo "configure: copying \"upnp/inc/upnpconfig.h\" to \"build/inc/upnpconfig.h\""
|
||||
cp upnp/inc/upnpconfig.h build/inc/upnpconfig.h
|
||||
|
@@ -7,7 +7,8 @@
|
||||
|
||||
SUBDIRS = doc
|
||||
|
||||
AM_CPPFLAGS = -I$(srcdir)/inc -I$(srcdir)/src/inc
|
||||
AM_CPPFLAGS = -I$(srcdir)/inc -I$(srcdir)/src/inc \
|
||||
-I$(top_srcdir)/upnp/inc
|
||||
AM_CFLAGS =
|
||||
|
||||
LDADD = libixml.la
|
||||
|
@@ -1,4 +1,4 @@
|
||||
Version: 1.6.18
|
||||
Version: 1.6.20
|
||||
Summary: Universal Plug and Play (UPnP) SDK
|
||||
Name: libupnp
|
||||
Release: 1%{?dist}
|
||||
|
@@ -4,7 +4,8 @@
|
||||
# (C) Copyright 2005 Remi Turboult <r3mi@users.sourceforge.net>
|
||||
#
|
||||
|
||||
AM_CPPFLAGS = -I$(srcdir)/inc -I$(srcdir)/src/inc
|
||||
AM_CPPFLAGS = -I$(srcdir)/inc -I$(srcdir)/src/inc \
|
||||
-I$(top_srcdir)/upnp/inc
|
||||
|
||||
if ENABLE_DEBUG
|
||||
AM_CPPFLAGS += -DDEBUG -DSTATS
|
||||
|
@@ -50,7 +50,7 @@ extern "C" {
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#if defined(BSD)
|
||||
#if defined(BSD) && !defined(__GNU__)
|
||||
#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
|
||||
#endif
|
||||
|
||||
@@ -200,10 +200,6 @@ typedef pthread_rwlockattr_t ithread_rwlockattr_t;
|
||||
static UPNP_INLINE int ithread_initialize_library(void) {
|
||||
int ret = 0;
|
||||
|
||||
#if defined(WIN32) && defined(PTW32_STATIC_LIB)
|
||||
ret = !pthread_win32_process_attach_np();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -222,10 +218,6 @@ static UPNP_INLINE int ithread_initialize_library(void) {
|
||||
static UPNP_INLINE int ithread_cleanup_library(void) {
|
||||
int ret = 0;
|
||||
|
||||
#if defined(WIN32) && defined(PTW32_STATIC_LIB)
|
||||
ret = !pthread_win32_process_detach_np();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@@ -96,10 +96,17 @@ static void *TimerThreadWorker(
|
||||
/* If time has elapsed, schedule job. */
|
||||
if (nextEvent && currentTime >= nextEventTime) {
|
||||
if( nextEvent->persistent ) {
|
||||
ThreadPoolAddPersistent( timer->tp, &nextEvent->job,
|
||||
&tempId );
|
||||
if (ThreadPoolAddPersistent( timer->tp, &nextEvent->job, &tempId ) != 0) {
|
||||
if (nextEvent->job.arg != NULL && nextEvent->job.free_func != NULL) {
|
||||
nextEvent->job.free_func(nextEvent->job.arg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ThreadPoolAdd( timer->tp, &nextEvent->job, &tempId );
|
||||
if (ThreadPoolAdd( timer->tp, &nextEvent->job, &tempId ) != 0) {
|
||||
if (nextEvent->job.arg != NULL && nextEvent->job.free_func != NULL) {
|
||||
nextEvent->job.free_func(nextEvent->job.arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
ListDelNode( &timer->eventQ, head, 0 );
|
||||
FreeTimerEvent( timer, nextEvent );
|
||||
|
@@ -154,9 +154,10 @@ libupnp_la_SOURCES += \
|
||||
|
||||
|
||||
# check / distcheck tests
|
||||
check_PROGRAMS = test_init
|
||||
TESTS = test_init
|
||||
check_PROGRAMS = test_init test_url
|
||||
TESTS = test_init test_url
|
||||
test_init_SOURCES = test/test_init.c
|
||||
test_url_SOURCES = test/test_url.c
|
||||
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
@@ -65,9 +65,8 @@ tv_combo_SOURCES = \
|
||||
if WITH_DOCUMENTATION
|
||||
examplesdir = $(docdir)/examples
|
||||
examples_DATA = \
|
||||
$(sort \
|
||||
$(tv_ctrlpt_SOURCES) \
|
||||
$(tv_device_SOURCES))
|
||||
$(tv_ctrlpt_SOURCES) \
|
||||
$(tv_device_SOURCES)
|
||||
endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
@@ -741,6 +741,10 @@ void TvCtrlPointAddDevice(
|
||||
deviceNode->device.AdvrTimeOut = expires;
|
||||
for (service = 0; service < TV_SERVICE_SERVCOUNT;
|
||||
service++) {
|
||||
if (serviceId[service] == NULL) {
|
||||
/* not found */
|
||||
continue;
|
||||
}
|
||||
strcpy(deviceNode->device.TvService[service].
|
||||
ServiceId, serviceId[service]);
|
||||
strcpy(deviceNode->device.TvService[service].
|
||||
|
@@ -43,9 +43,7 @@
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* strndup() is a GNU extension. */
|
||||
#if HAVE_STRNDUP && !defined(WIN32)
|
||||
extern char *strndup(__const char *__string, size_t __n);
|
||||
#else /* HAVE_STRNDUP && !defined(WIN32) */
|
||||
#if !HAVE_STRNDUP || defined(WIN32)
|
||||
static char *strndup(const char *__string, size_t __n)
|
||||
{
|
||||
size_t strsize = strnlen(__string, __n);
|
||||
|
@@ -1590,7 +1590,6 @@ static int GetDescDocumentAndURL(
|
||||
}
|
||||
if (strlen(temp_str) > (LINE_SIZE - 1)) {
|
||||
ixmlDocument_free(*xmlDoc);
|
||||
free(temp_str);
|
||||
return UPNP_E_URL_TOO_BIG;
|
||||
}
|
||||
strncpy(aliasStr, temp_str, sizeof(aliasStr) - 1);
|
||||
@@ -1981,7 +1980,9 @@ int UpnpSubscribeAsync(
|
||||
TPJobInit(&job, (start_routine)UpnpThreadDistribution, Param);
|
||||
TPJobSetFreeFunction(&job, (free_routine)free);
|
||||
TPJobSetPriority(&job, MED_PRIORITY);
|
||||
ThreadPoolAdd(&gSendThreadPool, &job, NULL);
|
||||
if (ThreadPoolAdd(&gSendThreadPool, &job, NULL) != 0) {
|
||||
free(Param);
|
||||
}
|
||||
|
||||
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
||||
"Exiting UpnpSubscribeAsync\n");
|
||||
@@ -2167,7 +2168,9 @@ int UpnpUnSubscribeAsync(
|
||||
TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
|
||||
TPJobSetFreeFunction( &job, ( free_routine ) free );
|
||||
TPJobSetPriority( &job, MED_PRIORITY );
|
||||
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
||||
if (ThreadPoolAdd( &gSendThreadPool, &job, NULL ) != 0) {
|
||||
free(Param);
|
||||
}
|
||||
|
||||
exit_function:
|
||||
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpUnSubscribeAsync\n");
|
||||
@@ -2293,7 +2296,9 @@ int UpnpRenewSubscriptionAsync(
|
||||
TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
|
||||
TPJobSetFreeFunction( &job, ( free_routine ) free );
|
||||
TPJobSetPriority( &job, MED_PRIORITY );
|
||||
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
||||
if (ThreadPoolAdd( &gSendThreadPool, &job, NULL ) != 0) {
|
||||
free(Param);
|
||||
}
|
||||
|
||||
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
||||
"Exiting UpnpRenewSubscriptionAsync\n");
|
||||
@@ -2765,7 +2770,9 @@ int UpnpSendActionAsync(
|
||||
TPJobSetFreeFunction( &job, ( free_routine ) free );
|
||||
|
||||
TPJobSetPriority( &job, MED_PRIORITY );
|
||||
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
||||
if (ThreadPoolAdd( &gSendThreadPool, &job, NULL ) != 0) {
|
||||
free(Param);
|
||||
}
|
||||
|
||||
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
||||
"Exiting UpnpSendActionAsync \n");
|
||||
@@ -2885,7 +2892,9 @@ int UpnpSendActionExAsync(
|
||||
TPJobSetFreeFunction( &job, ( free_routine ) free );
|
||||
|
||||
TPJobSetPriority( &job, MED_PRIORITY );
|
||||
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
||||
if (ThreadPoolAdd( &gSendThreadPool, &job, NULL ) != 0) {
|
||||
free(Param);
|
||||
}
|
||||
|
||||
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
||||
"Exiting UpnpSendActionAsync\n");
|
||||
@@ -2952,7 +2961,9 @@ int UpnpGetServiceVarStatusAsync(
|
||||
|
||||
TPJobSetPriority( &job, MED_PRIORITY );
|
||||
|
||||
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
||||
if (ThreadPoolAdd( &gSendThreadPool, &job, NULL ) != 0) {
|
||||
free(Param);
|
||||
}
|
||||
|
||||
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
||||
"Exiting UpnpGetServiceVarStatusAsync\n");
|
||||
@@ -4085,16 +4096,17 @@ int UpnpRemoveVirtualDir(const char *dirName)
|
||||
return UPNP_E_INVALID_PARAM;
|
||||
}
|
||||
/* Handle the special case where the directory that we are */
|
||||
/* removing is the first and only one in the list. */
|
||||
if( ( pVirtualDirList->next == NULL ) &&
|
||||
( strcmp( pVirtualDirList->dirName, dirName ) == 0 ) ) {
|
||||
free( pVirtualDirList );
|
||||
pVirtualDirList = NULL;
|
||||
/* removing is the first in the list. */
|
||||
if (strcmp( pVirtualDirList->dirName, dirName ) == 0)
|
||||
{
|
||||
pPrev = pVirtualDirList;
|
||||
pVirtualDirList = pVirtualDirList->next;
|
||||
free( pPrev );
|
||||
return UPNP_E_SUCCESS;
|
||||
}
|
||||
|
||||
pCur = pVirtualDirList;
|
||||
pPrev = pCur;
|
||||
pCur = pVirtualDirList->next;
|
||||
pPrev = pVirtualDirList;
|
||||
|
||||
while( pCur != NULL ) {
|
||||
if( strcmp( pCur->dirName, dirName ) == 0 ) {
|
||||
|
@@ -480,25 +480,20 @@ int genaInitNotify(
|
||||
}
|
||||
*reference_count = 0;
|
||||
|
||||
UDN_copy = (char *)malloc(strlen(UDN) + 1);
|
||||
UDN_copy = strdup(UDN);
|
||||
if (UDN_copy == NULL) {
|
||||
line = __LINE__;
|
||||
ret = UPNP_E_OUTOF_MEMORY;
|
||||
goto ExitFunction;
|
||||
}
|
||||
|
||||
servId_copy = (char *)malloc(strlen(servId) + 1);
|
||||
servId_copy = strdup(servId);
|
||||
if (servId_copy == NULL) {
|
||||
line = __LINE__;
|
||||
ret = UPNP_E_OUTOF_MEMORY;
|
||||
goto ExitFunction;
|
||||
}
|
||||
|
||||
memset(UDN_copy, 0, strlen(UDN) + 1);
|
||||
strncpy(UDN_copy, UDN, strlen(UDN));
|
||||
memset(servId_copy, 0, strlen(servId) + 1);
|
||||
strncpy(servId_copy, servId, strlen(servId));
|
||||
|
||||
HandleLock();
|
||||
|
||||
if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
|
||||
@@ -639,25 +634,20 @@ int genaInitNotifyExt(
|
||||
}
|
||||
*reference_count = 0;
|
||||
|
||||
UDN_copy = (char *)malloc(strlen(UDN) + 1);
|
||||
UDN_copy = strdup(UDN);
|
||||
if (UDN_copy == NULL) {
|
||||
line = __LINE__;
|
||||
ret = UPNP_E_OUTOF_MEMORY;
|
||||
goto ExitFunction;
|
||||
}
|
||||
|
||||
servId_copy = (char *)malloc(strlen(servId) + 1);
|
||||
servId_copy = strdup(servId);
|
||||
if( servId_copy == NULL ) {
|
||||
line = __LINE__;
|
||||
ret = UPNP_E_OUTOF_MEMORY;
|
||||
goto ExitFunction;
|
||||
}
|
||||
|
||||
memset(UDN_copy, 0, strlen(UDN) + 1);
|
||||
strncpy(UDN_copy, UDN, strlen(UDN));
|
||||
memset(servId_copy, 0, strlen(servId) + 1);
|
||||
strncpy(servId_copy, servId, strlen(servId));
|
||||
|
||||
HandleLock();
|
||||
|
||||
if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
|
||||
@@ -798,25 +788,20 @@ int genaNotifyAllExt(
|
||||
}
|
||||
*reference_count = 0;
|
||||
|
||||
UDN_copy = (char *)malloc(strlen(UDN) + 1);
|
||||
UDN_copy = strdup(UDN);
|
||||
if (UDN_copy == NULL) {
|
||||
line = __LINE__;
|
||||
ret = UPNP_E_OUTOF_MEMORY;
|
||||
goto ExitFunction;
|
||||
}
|
||||
|
||||
servId_copy = (char *)malloc(strlen(servId) + 1);
|
||||
servId_copy = strdup(servId);
|
||||
if( servId_copy == NULL ) {
|
||||
line = __LINE__;
|
||||
ret = UPNP_E_OUTOF_MEMORY;
|
||||
goto ExitFunction;
|
||||
}
|
||||
|
||||
memset(UDN_copy, 0, strlen(UDN) + 1);
|
||||
strncpy(UDN_copy, UDN, strlen(UDN));
|
||||
memset(servId_copy, 0, strlen(servId) + 1);
|
||||
strncpy(servId_copy, servId, strlen(servId));
|
||||
|
||||
propertySet = ixmlPrintNode((IXML_Node *)PropSet);
|
||||
if (propertySet == NULL) {
|
||||
line = __LINE__;
|
||||
@@ -944,25 +929,20 @@ int genaNotifyAll(
|
||||
}
|
||||
*reference_count = 0;
|
||||
|
||||
UDN_copy = (char *)malloc(strlen(UDN) + 1);
|
||||
UDN_copy = strdup(UDN);
|
||||
if (UDN_copy == NULL) {
|
||||
line = __LINE__;
|
||||
ret = UPNP_E_OUTOF_MEMORY;
|
||||
goto ExitFunction;
|
||||
}
|
||||
|
||||
servId_copy = (char *)malloc(strlen(servId) + 1);
|
||||
servId_copy = strdup(servId);
|
||||
if( servId_copy == NULL ) {
|
||||
line = __LINE__;
|
||||
ret = UPNP_E_OUTOF_MEMORY;
|
||||
goto ExitFunction;
|
||||
}
|
||||
|
||||
memset(UDN_copy, 0, strlen(UDN) + 1);
|
||||
strncpy(UDN_copy, UDN, strlen(UDN));
|
||||
memset(servId_copy, 0, strlen(servId) + 1);
|
||||
strncpy(servId_copy, servId, strlen(servId));
|
||||
|
||||
ret = GeneratePropertySet(VarNames, VarValues, var_count, &propertySet);
|
||||
if (ret != XML_SUCCESS) {
|
||||
line = __LINE__;
|
||||
|
@@ -910,6 +910,7 @@ int StartMiniServer(
|
||||
sock_close(miniSocket->ssdpReqSock4);
|
||||
sock_close(miniSocket->ssdpReqSock6);
|
||||
#endif /* INCLUDE_CLIENT_APIS */
|
||||
free(miniSocket);
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
}
|
||||
/* Wait for miniserver to start. */
|
||||
|
@@ -138,12 +138,12 @@ static UPNP_INLINE void scanner_init(OUT scanner_t *scanner, IN membuffer *bufpt
|
||||
* Parameters :
|
||||
* IN char c ; character to be tested against used separator values
|
||||
*
|
||||
* Description : Finds the separator character.
|
||||
* Description : Determines if the passed value is a separator
|
||||
*
|
||||
************************************************************************/
|
||||
static UPNP_INLINE int is_separator_char(IN char c)
|
||||
static UPNP_INLINE int is_separator_char(IN int c)
|
||||
{
|
||||
return strchr(" \t()<>@,;:\\\"/[]?={}", (int)c) != NULL;
|
||||
return strchr(" \t()<>@,;:\\\"/[]?={}", c) != 0;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
@@ -152,10 +152,10 @@ static UPNP_INLINE int is_separator_char(IN char c)
|
||||
* Parameters :
|
||||
* IN char c ; character to be tested for separator values
|
||||
*
|
||||
* Description : Calls the function to indentify separator character
|
||||
* Description : Determines if the passed value is permissible in token
|
||||
*
|
||||
************************************************************************/
|
||||
static UPNP_INLINE int is_identifier_char(IN char c)
|
||||
static UPNP_INLINE int is_identifier_char(IN int c)
|
||||
{
|
||||
return c >= 32 && c <= 126 && !is_separator_char(c);
|
||||
}
|
||||
@@ -169,7 +169,7 @@ static UPNP_INLINE int is_identifier_char(IN char c)
|
||||
* Description : Determines if the passed value is a control character
|
||||
*
|
||||
************************************************************************/
|
||||
static UPNP_INLINE int is_control_char(IN char c)
|
||||
static UPNP_INLINE int is_control_char(IN int c)
|
||||
{
|
||||
return (c >= 0 && c <= 31) || c == 127;
|
||||
}
|
||||
@@ -180,23 +180,20 @@ static UPNP_INLINE int is_control_char(IN char c)
|
||||
* Parameters :
|
||||
* IN char cc ; character to be tested for CR/LF
|
||||
*
|
||||
* Description : Checks to see if the passed in value is CR/LF
|
||||
* Description : Determines if the passed value is permissible in qdtext
|
||||
*
|
||||
************************************************************************/
|
||||
static UPNP_INLINE int is_qdtext_char(IN char cc)
|
||||
static UPNP_INLINE int is_qdtext_char(IN int c)
|
||||
{
|
||||
unsigned char c = ( unsigned char )cc;
|
||||
/* we don't check for this; it's checked in get_token() */
|
||||
assert( c != '"' );
|
||||
|
||||
/* we don't check for this; it's checked in get_token() */
|
||||
assert( c != '"' );
|
||||
|
||||
if( ( c >= 32 && c != 127 ) ||
|
||||
( c == TOKCHAR_CR || c == TOKCHAR_LF || c == '\t' )
|
||||
) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
return
|
||||
(c >= 32 && c != 127) ||
|
||||
c < 0 ||
|
||||
c == TOKCHAR_CR ||
|
||||
c == TOKCHAR_LF ||
|
||||
c == '\t';
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
@@ -224,7 +221,7 @@ static parse_status_t scanner_get_token(
|
||||
{
|
||||
char *cursor;
|
||||
char *null_terminator; /* point to null-terminator in buffer */
|
||||
char c;
|
||||
int c;
|
||||
token_type_t token_type;
|
||||
int got_end_quote;
|
||||
|
||||
@@ -243,7 +240,7 @@ static parse_status_t scanner_get_token(
|
||||
/* scan identifier */
|
||||
token->buf = cursor++;
|
||||
token_type = TT_IDENTIFIER;
|
||||
while (is_identifier_char(*cursor))
|
||||
while (cursor < null_terminator && is_identifier_char(*cursor))
|
||||
cursor++;
|
||||
if (!scanner->entire_msg_loaded && cursor == null_terminator)
|
||||
/* possibly more valid chars */
|
||||
@@ -253,7 +250,7 @@ static parse_status_t scanner_get_token(
|
||||
} else if (c == ' ' || c == '\t') {
|
||||
token->buf = cursor++;
|
||||
token_type = TT_WHITESPACE;
|
||||
while (*cursor == ' ' || *cursor == '\t')
|
||||
while (cursor < null_terminator && (*cursor == ' ' || *cursor == '\t'))
|
||||
cursor++;
|
||||
if (!scanner->entire_msg_loaded && cursor == null_terminator)
|
||||
/* possibly more chars */
|
||||
@@ -292,9 +289,7 @@ static parse_status_t scanner_get_token(
|
||||
} else if (c == '\\') {
|
||||
if (cursor < null_terminator) {
|
||||
c = *cursor++;
|
||||
/*if ( !(c > 0 && c <= 127) ) */
|
||||
if (c == 0)
|
||||
return PARSE_FAILURE;
|
||||
/* the char after '\\' could be ANY octet */
|
||||
}
|
||||
/* else, while loop handles incomplete buf */
|
||||
} else if (is_qdtext_char(c)) {
|
||||
@@ -521,8 +516,9 @@ http_header_t *httpmsg_find_hdr(
|
||||
* Description : skips blank lines at the start of a msg.
|
||||
*
|
||||
* Return : parse_status_t ;
|
||||
*
|
||||
* Note :
|
||||
* PARSE_OK
|
||||
* PARSE_INCOMPLETE -- not enuf chars to get a token
|
||||
* PARSE_FAILURE -- bad msg format
|
||||
************************************************************************/
|
||||
static UPNP_INLINE parse_status_t skip_blank_lines(INOUT scanner_t *scanner)
|
||||
{
|
||||
@@ -1132,6 +1128,7 @@ static parse_status_t vfmatch(
|
||||
* PARSE_OK
|
||||
* PARSE_NO_MATCH
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_FAILURE - bad input
|
||||
************************************************************************/
|
||||
static parse_status_t match(
|
||||
INOUT scanner_t *scanner,
|
||||
@@ -1164,6 +1161,7 @@ static parse_status_t match(
|
||||
* PARSE_OK
|
||||
* PARSE_NO_MATCH -- failure to match pattern 'fmt'
|
||||
* PARSE_FAILURE -- 'str' is bad input
|
||||
* PARSE_INCOMPLETE
|
||||
************************************************************************/
|
||||
parse_status_t
|
||||
matchstr( IN char *str,
|
||||
@@ -1238,6 +1236,8 @@ parser_init( OUT http_parser_t * parser )
|
||||
* PARSE_OK
|
||||
* PARSE_SUCCESS
|
||||
* PARSE_FAILURE
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_NO_MATCH
|
||||
************************************************************************/
|
||||
static parse_status_t
|
||||
parser_parse_requestline( INOUT http_parser_t * parser )
|
||||
@@ -1354,12 +1354,13 @@ parser_parse_requestline( INOUT http_parser_t * parser )
|
||||
* Parameters:
|
||||
* INOUT http_parser_t* parser ; HTTP Parser object
|
||||
*
|
||||
* Description: Get HTTP Method, URL location and version information.
|
||||
* Description: Get HTTP version information, status code and status msg.
|
||||
*
|
||||
* Returns:
|
||||
* PARSE_OK
|
||||
* PARSE_SUCCESS
|
||||
* PARSE_FAILURE
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_NO_MATCH
|
||||
************************************************************************/
|
||||
parse_status_t parser_parse_responseline(INOUT http_parser_t *parser)
|
||||
{
|
||||
@@ -1431,12 +1432,14 @@ parse_status_t parser_parse_responseline(INOUT http_parser_t *parser)
|
||||
* Parameters:
|
||||
* INOUT http_parser_t* parser ; HTTP Parser object
|
||||
*
|
||||
* Description: Get HTTP Method, URL location and version information.
|
||||
* Description: Read HTTP header fields.
|
||||
*
|
||||
* Returns:
|
||||
* PARSE_OK
|
||||
* PARSE_SUCCESS
|
||||
* PARSE_FAILURE
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_NO_MATCH
|
||||
************************************************************************/
|
||||
parse_status_t parser_parse_headers(INOUT http_parser_t *parser)
|
||||
{
|
||||
@@ -1462,6 +1465,8 @@ parse_status_t parser_parse_headers(INOUT http_parser_t *parser)
|
||||
/* check end of headers */
|
||||
status = scanner_get_token(scanner, &token, &tok_type);
|
||||
if (status != (parse_status_t)PARSE_OK) {
|
||||
/* pushback tokens; useful only on INCOMPLETE error */
|
||||
scanner->cursor = save_pos;
|
||||
return status;
|
||||
}
|
||||
switch (tok_type) {
|
||||
@@ -1529,6 +1534,8 @@ parse_status_t parser_parse_headers(INOUT http_parser_t *parser)
|
||||
if (membuffer_assign(&header->name_buf, token.buf, token.length) ||
|
||||
membuffer_assign(&header->value, hdr_value.buf, hdr_value.length)) {
|
||||
/* not enough mem */
|
||||
membuffer_destroy(&header->value);
|
||||
membuffer_destroy(&header->name_buf);
|
||||
free(header);
|
||||
parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR;
|
||||
return PARSE_FAILURE;
|
||||
@@ -1536,15 +1543,13 @@ parse_status_t parser_parse_headers(INOUT http_parser_t *parser)
|
||||
header->name.buf = header->name_buf.buf;
|
||||
header->name.length = header->name_buf.length;
|
||||
header->name_id = header_id;
|
||||
ListAddTail(&parser->msg.headers, header);
|
||||
/*NNS: ret = dlist_append( &parser->msg.headers, header ); */
|
||||
/** TODO: remove that? Yes as ret is not set anymore
|
||||
if (ret == UPNP_E_OUTOF_MEMORY) {
|
||||
parser->http_error_code =
|
||||
HTTP_INTERNAL_SERVER_ERROR;
|
||||
if (!ListAddTail(&parser->msg.headers, header)) {
|
||||
membuffer_destroy(&header->value);
|
||||
membuffer_destroy(&header->name_buf);
|
||||
free(header);
|
||||
parser->http_error_code = HTTP_INTERNAL_SERVER_ERROR;
|
||||
return PARSE_FAILURE;
|
||||
}
|
||||
end of remove that? */
|
||||
} else if (hdr_value.length > (size_t)0) {
|
||||
/* append value to existing header */
|
||||
/* append space */
|
||||
@@ -1575,7 +1580,6 @@ end of remove that? */
|
||||
*
|
||||
* Returns:
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_FAILURE -- entity length > content-length value
|
||||
* PARSE_SUCCESS
|
||||
************************************************************************/
|
||||
static UPNP_INLINE parse_status_t
|
||||
@@ -1622,9 +1626,10 @@ parser_parse_entity_using_clen( INOUT http_parser_t * parser )
|
||||
* Description: Read data in the chunks
|
||||
*
|
||||
* Returns:
|
||||
* PARSE_CONTINUE_1
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_FAILURE -- entity length > content-length value
|
||||
* PARSE_SUCCESS
|
||||
* PARSE_FAILURE
|
||||
* PARSE_NO_MATCH
|
||||
************************************************************************/
|
||||
static UPNP_INLINE parse_status_t parser_parse_chunky_body(
|
||||
INOUT http_parser_t *parser)
|
||||
@@ -1666,8 +1671,9 @@ static UPNP_INLINE parse_status_t parser_parse_chunky_body(
|
||||
* Description: Read headers at the end of the chunked entity
|
||||
*
|
||||
* Returns:
|
||||
* PARSE_NO_MATCH
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_FAILURE -- entity length > content-length value
|
||||
* PARSE_FAILURE
|
||||
* PARSE_SUCCESS
|
||||
************************************************************************/
|
||||
static UPNP_INLINE parse_status_t
|
||||
@@ -1702,12 +1708,12 @@ parser_parse_chunky_headers( INOUT http_parser_t * parser )
|
||||
* Parameters:
|
||||
* INOUT http_parser_t* parser - HTTP Parser Object
|
||||
*
|
||||
* Description: Read headers at the end of the chunked entity
|
||||
* Description: Read entity using chunked transfer encoding
|
||||
*
|
||||
* Returns:
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_FAILURE -- entity length > content-length value
|
||||
* PARSE_SUCCESS
|
||||
* PARSE_FAILURE
|
||||
* PARSE_NO_MATCH
|
||||
* PARSE_CONTINUE_1
|
||||
************************************************************************/
|
||||
static UPNP_INLINE parse_status_t
|
||||
@@ -1756,7 +1762,7 @@ parser_parse_chunky_entity( INOUT http_parser_t * parser )
|
||||
* Parameters:
|
||||
* INOUT http_parser_t* parser ; HTTP Parser object
|
||||
*
|
||||
* Description: Read headers at the end of the chunked entity
|
||||
* Description: Keep reading entity until the connection is closed.
|
||||
*
|
||||
* Returns:
|
||||
* PARSE_INCOMPLETE_ENTITY
|
||||
@@ -1793,9 +1799,9 @@ parser_parse_entity_until_close( INOUT http_parser_t * parser )
|
||||
* Description: Determines method to read entity
|
||||
*
|
||||
* Returns:
|
||||
* PARSE_OK
|
||||
* PARSE_CONTINUE_1
|
||||
* PARSE_FAILURE
|
||||
* PARSE_COMPLETE -- no more reading to do
|
||||
* PARSE_SUCCESS -- no more reading to do
|
||||
************************************************************************/
|
||||
UPNP_INLINE parse_status_t
|
||||
parser_get_entity_read_method( INOUT http_parser_t * parser )
|
||||
@@ -1891,17 +1897,19 @@ parser_get_entity_read_method( INOUT http_parser_t * parser )
|
||||
* Parameters:
|
||||
* INOUT http_parser_t* parser ; HTTP Parser object
|
||||
*
|
||||
* Description: Determines method to read entity
|
||||
* Description: Read HTTP entity body
|
||||
*
|
||||
* Returns:
|
||||
* PARSE_OK
|
||||
* PARSE_FAILURE
|
||||
* PARSE_COMPLETE -- no more reading to do
|
||||
* PARSE_NO_MATCH
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_INCOMPLETE_ENTITY
|
||||
* PARSE_SUCCESS -- no more reading to do
|
||||
************************************************************************/
|
||||
UPNP_INLINE parse_status_t
|
||||
parser_parse_entity( INOUT http_parser_t * parser )
|
||||
{
|
||||
parse_status_t status = PARSE_OK;
|
||||
parse_status_t status;
|
||||
|
||||
assert( parser->position == POS_ENTITY );
|
||||
|
||||
@@ -1932,6 +1940,7 @@ parser_parse_entity( INOUT http_parser_t * parser )
|
||||
break;
|
||||
|
||||
default:
|
||||
status = PARSE_FAILURE;
|
||||
assert( 0 );
|
||||
}
|
||||
|
||||
@@ -1992,7 +2001,11 @@ parser_response_init( OUT http_parser_t * parser,
|
||||
* parser object the actual parsing function is invoked
|
||||
*
|
||||
* Returns:
|
||||
* void
|
||||
* PARSE_SUCCESS
|
||||
* PARSE_FAILURE
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_INCOMPLETE_ENTITY
|
||||
* PARSE_NO_MATCH
|
||||
************************************************************************/
|
||||
parse_status_t
|
||||
parser_parse( INOUT http_parser_t * parser )
|
||||
@@ -2047,11 +2060,14 @@ parser_parse( INOUT http_parser_t * parser )
|
||||
* buffer
|
||||
* IN size_t buf_length ; Size of the buffer
|
||||
*
|
||||
* Description: The parser function. Depending on the position of the
|
||||
* parser object the actual parsing function is invoked
|
||||
* Description: Append date to HTTP parser, and do the parsing.
|
||||
*
|
||||
* Returns:
|
||||
* void
|
||||
* PARSE_SUCCESS
|
||||
* PARSE_FAILURE
|
||||
* PARSE_INCOMPLETE
|
||||
* PARSE_INCOMPLETE_ENTITY
|
||||
* PARSE_NO_MATCH
|
||||
************************************************************************/
|
||||
parse_status_t
|
||||
parser_append( INOUT http_parser_t * parser,
|
||||
|
@@ -322,6 +322,7 @@ int http_RecvMessage(
|
||||
ret = 0;
|
||||
goto ExitFunction;
|
||||
case PARSE_FAILURE:
|
||||
case PARSE_NO_MATCH:
|
||||
*http_error_code = parser->http_error_code;
|
||||
line = __LINE__;
|
||||
ret = UPNP_E_BAD_HTTPMSG;
|
||||
@@ -480,13 +481,12 @@ int http_SendMessage(SOCKINFO *info, int *TimeOut, const char *fmt, ...)
|
||||
memset(Chunk_Header, 0,
|
||||
sizeof(Chunk_Header));
|
||||
rc = snprintf(Chunk_Header,
|
||||
sizeof(Chunk_Header) - strlen ("\r\n"),
|
||||
"%" PRIzx, num_read);
|
||||
if (rc < 0 || (unsigned int) rc >= sizeof(Chunk_Header) - strlen ("\r\n")) {
|
||||
sizeof(Chunk_Header),
|
||||
"%" PRIzx "\r\n", num_read);
|
||||
if (rc < 0 || (unsigned int) rc >= sizeof(Chunk_Header)) {
|
||||
RetVal = UPNP_E_INTERNAL_ERROR;
|
||||
goto Cleanup_File;
|
||||
}
|
||||
strncat(Chunk_Header, "\r\n", strlen ("\r\n"));
|
||||
/* Copy the chunk size header */
|
||||
memcpy(file_buf - strlen(Chunk_Header),
|
||||
Chunk_Header,
|
||||
|
@@ -88,14 +88,19 @@ static const char *Http4xxStr =
|
||||
"Unsupported Media Type\0"
|
||||
"Requested Range Not Satisfiable\0" "Expectation Failed\0";
|
||||
|
||||
#define NUM_5XX_CODES 6
|
||||
#define NUM_5XX_CODES 11
|
||||
static const char *Http5xxCodes[NUM_5XX_CODES];
|
||||
static const char *Http5xxStr =
|
||||
"Internal Server Error\0"
|
||||
"Not Implemented\0"
|
||||
"Bad Gateway\0"
|
||||
"Service Unavailable\0"
|
||||
"Gateway Timeout\0" "HTTP Version Not Supported\0";
|
||||
"Gateway Timeout\0"
|
||||
"HTTP Version Not Supported\0"
|
||||
"Variant Also Negotiates\0"
|
||||
"Insufficient Storage\0"
|
||||
"Loop Detected\0"
|
||||
"\0" "Not Extended\0";
|
||||
|
||||
static int gInitialized = FALSE;
|
||||
|
||||
|
@@ -129,7 +129,7 @@ static const char *gMediaTypes[] = {
|
||||
#define TEXT_INDEX 5
|
||||
|
||||
/* general */
|
||||
#define NUM_MEDIA_TYPES 69
|
||||
#define NUM_MEDIA_TYPES 70
|
||||
#define NUM_HTTP_HEADER_NAMES 33
|
||||
|
||||
#define ASCTIME_R_BUFFER_SIZE 26
|
||||
@@ -156,6 +156,7 @@ static const char *gEncodedMediaTypes =
|
||||
"au\0" AUDIO_STR "basic\0"
|
||||
"avi\0" VIDEO_STR "msvideo\0"
|
||||
"bmp\0" IMAGE_STR "bmp\0"
|
||||
"css\0" TEXT_STR "css\0"
|
||||
"dcr\0" APPLICATION_STR "x-director\0"
|
||||
"dib\0" IMAGE_STR "bmp\0"
|
||||
"dir\0" APPLICATION_STR "x-director\0"
|
||||
@@ -771,7 +772,7 @@ static int GetNextRange(
|
||||
*
|
||||
* \return
|
||||
* \li \c HTTP_BAD_REQUEST
|
||||
* \li \c UPNP_E_OUTOF_MEMORY
|
||||
* \li \c HTTP_INTERNAL_SERVER_ERROR
|
||||
* \li \c HTTP_REQUEST_RANGE_NOT_SATISFIABLE
|
||||
* \li \c HTTP_OK
|
||||
*/
|
||||
@@ -792,11 +793,9 @@ static int CreateHTTPRangeResponseHeader(
|
||||
Instr->ReadSendSize = FileLength;
|
||||
if (!ByteRangeSpecifier)
|
||||
return HTTP_BAD_REQUEST;
|
||||
RangeInput = malloc(strlen(ByteRangeSpecifier) + 1);
|
||||
RangeInput = strdup(ByteRangeSpecifier);
|
||||
if (!RangeInput)
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
memset(RangeInput, 0, strlen(ByteRangeSpecifier) + 1);
|
||||
strncpy(RangeInput, ByteRangeSpecifier, strlen(ByteRangeSpecifier));
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
/* CONTENT-RANGE: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT */
|
||||
if (StrStr(RangeInput, "bytes") == NULL ||
|
||||
(Ptr = StrStr(RangeInput, "=")) == NULL) {
|
||||
@@ -830,7 +829,7 @@ static int CreateHTTPRangeResponseHeader(
|
||||
(int64_t)FileLength);
|
||||
if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) {
|
||||
free(RangeInput);
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
} else if (FirstByte >= 0 && LastByte == -1
|
||||
&& FirstByte < FileLength) {
|
||||
@@ -845,7 +844,7 @@ static int CreateHTTPRangeResponseHeader(
|
||||
(int64_t)FileLength);
|
||||
if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) {
|
||||
free(RangeInput);
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
} else if (FirstByte == -1 && LastByte > 0) {
|
||||
if (LastByte >= FileLength) {
|
||||
@@ -864,13 +863,13 @@ static int CreateHTTPRangeResponseHeader(
|
||||
sizeof(Instr->RangeHeader),
|
||||
"CONTENT-RANGE: bytes %" PRId64
|
||||
"-%" PRId64 "/%" PRId64 "\r\n",
|
||||
(int64_t)(FileLength - LastByte + 1),
|
||||
(int64_t)FileLength,
|
||||
(int64_t)(FileLength - LastByte),
|
||||
(int64_t)FileLength - 1,
|
||||
(int64_t)FileLength);
|
||||
}
|
||||
if (rc < 0 || (unsigned int) rc >= sizeof(Instr->RangeHeader)) {
|
||||
free(RangeInput);
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
} else {
|
||||
free(RangeInput);
|
||||
@@ -891,7 +890,7 @@ static int CreateHTTPRangeResponseHeader(
|
||||
*
|
||||
* \return
|
||||
* \li \c HTTP_BAD_REQUEST
|
||||
* \li \c UPNP_E_OUTOF_MEMORY
|
||||
* \li \c HTTP_INTERNAL_SERVER_ERROR
|
||||
* \li \c HTTP_REQUEST_RANGE_NOT_SATISFIABLE
|
||||
* \li \c HTTP_OK
|
||||
*/
|
||||
@@ -912,7 +911,7 @@ static int CheckOtherHTTPHeaders(
|
||||
|
||||
TmpBuf = (char *)malloc(TmpBufSize);
|
||||
if (!TmpBuf)
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
node = ListHead(&Req->headers);
|
||||
while (node != NULL) {
|
||||
header = (http_header_t *) node->item;
|
||||
@@ -925,7 +924,7 @@ static int CheckOtherHTTPHeaders(
|
||||
TmpBufSize = header->value.length + 1;
|
||||
TmpBuf = (char *)malloc(TmpBufSize);
|
||||
if (!TmpBuf)
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
memcpy(TmpBuf, header->value.buf, header->value.length);
|
||||
TmpBuf[header->value.length] = '\0';
|
||||
@@ -1014,8 +1013,11 @@ static int CheckOtherHTTPHeaders(
|
||||
*
|
||||
* \return
|
||||
* \li \c HTTP_BAD_REQUEST
|
||||
* \li \c UPNP_E_OUTOF_MEMORY
|
||||
* \li \c HTTP_INTERNAL_SERVER_ERROR
|
||||
* \li \c HTTP_REQUEST_RANGE_NOT_SATISFIABLE
|
||||
* \li \c HTTP_FORBIDDEN
|
||||
* \li \c HTTP_NOT_FOUND
|
||||
* \li \c HTTP_NOT_ACCEPTABLE
|
||||
* \li \c HTTP_OK
|
||||
*/
|
||||
static int process_request(
|
||||
@@ -1202,14 +1204,15 @@ static int process_request(
|
||||
}
|
||||
RespInstr->ReadSendSize = finfo.file_length;
|
||||
/* Check other header field. */
|
||||
if ((err_code =
|
||||
if ((code =
|
||||
CheckOtherHTTPHeaders(req, RespInstr,
|
||||
finfo.file_length)) != HTTP_OK) {
|
||||
err_code = code;
|
||||
goto error_handler;
|
||||
}
|
||||
if (req->method == HTTPMETHOD_POST) {
|
||||
*rtype = RESP_POST;
|
||||
err_code = UPNP_E_SUCCESS;
|
||||
err_code = HTTP_OK;
|
||||
goto error_handler;
|
||||
}
|
||||
/*extra_headers = UpnpFileInfo_get_ExtraHeaders(finfo); */
|
||||
@@ -1247,7 +1250,6 @@ static int process_request(
|
||||
}
|
||||
} else if (RespInstr->IsRangeActive && !RespInstr->IsChunkActive) {
|
||||
/* Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT */
|
||||
/* Transfer-Encoding: chunked */
|
||||
if (http_MakeMessage(headers, resp_major, resp_minor,
|
||||
"R" "N" "T" "GLD" "s" "tcS" "Xc" "sCc",
|
||||
HTTP_PARTIAL_CONTENT, /* status code */
|
||||
@@ -1261,7 +1263,6 @@ static int process_request(
|
||||
goto error_handler;
|
||||
}
|
||||
} else if (!RespInstr->IsRangeActive && RespInstr->IsChunkActive) {
|
||||
/* Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT */
|
||||
/* Transfer-Encoding: chunked */
|
||||
if (http_MakeMessage(headers, resp_major, resp_minor,
|
||||
"RK" "TLD" "s" "tcS" "Xc" "sCc",
|
||||
@@ -1276,8 +1277,6 @@ static int process_request(
|
||||
} else {
|
||||
/* !RespInstr->IsRangeActive && !RespInstr->IsChunkActive */
|
||||
if (RespInstr->ReadSendSize >= 0) {
|
||||
/* Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT */
|
||||
/* Transfer-Encoding: chunked */
|
||||
if (http_MakeMessage(headers, resp_major, resp_minor,
|
||||
"R" "N" "TLD" "s" "tcS" "Xc" "sCc",
|
||||
HTTP_OK, /* status code */
|
||||
@@ -1291,8 +1290,6 @@ static int process_request(
|
||||
goto error_handler;
|
||||
}
|
||||
} else {
|
||||
/* Content-Range: bytes 222-3333/4000 HTTP_PARTIAL_CONTENT */
|
||||
/* Transfer-Encoding: chunked */
|
||||
if (http_MakeMessage(headers, resp_major, resp_minor,
|
||||
"R" "TLD" "s" "tcS" "Xc" "sCc",
|
||||
HTTP_OK, /* status code */
|
||||
@@ -1322,12 +1319,12 @@ static int process_request(
|
||||
if (req->method == HTTPMETHOD_SIMPLEGET) {
|
||||
membuffer_destroy(headers);
|
||||
}
|
||||
err_code = UPNP_E_SUCCESS;
|
||||
err_code = HTTP_OK;
|
||||
|
||||
error_handler:
|
||||
free(request_doc);
|
||||
ixmlFreeDOMString(finfo.content_type);
|
||||
if (err_code != UPNP_E_SUCCESS && alias_grabbed) {
|
||||
if (err_code != HTTP_OK && alias_grabbed) {
|
||||
alias_release(alias);
|
||||
}
|
||||
|
||||
@@ -1340,7 +1337,8 @@ static int process_request(
|
||||
* \return
|
||||
* \li \c HTTP_INTERNAL_SERVER_ERROR
|
||||
* \li \c HTTP_UNAUTHORIZED
|
||||
* \li \c HTTP_REQUEST_RANGE_NOT_SATISFIABLE
|
||||
* \li \c HTTP_BAD_REQUEST
|
||||
* \li \c HTTP_SERVICE_UNAVAILABLE
|
||||
* \li \c HTTP_OK
|
||||
*/
|
||||
static int http_RecvPostMessage(
|
||||
@@ -1426,7 +1424,7 @@ static int http_RecvPostMessage(
|
||||
goto ExitFunction;
|
||||
}
|
||||
} else {
|
||||
ret_code = num_read;
|
||||
ret_code = HTTP_SERVICE_UNAVAILABLE;
|
||||
goto ExitFunction;
|
||||
}
|
||||
}
|
||||
@@ -1489,7 +1487,7 @@ void web_server_callback(http_parser_t *parser, INOUT http_message_t *req,
|
||||
/*the type of request. */
|
||||
ret = process_request(req, &rtype, &headers, &filename, &xmldoc,
|
||||
&RespInstr);
|
||||
if (ret != UPNP_E_SUCCESS) {
|
||||
if (ret != HTTP_OK) {
|
||||
/* send error code */
|
||||
http_SendStatusResponse(info, ret, req->major_version,
|
||||
req->minor_version);
|
||||
@@ -1531,7 +1529,7 @@ void web_server_callback(http_parser_t *parser, INOUT http_message_t *req,
|
||||
/* Send response. */
|
||||
http_MakeMessage(&headers, 1, 1,
|
||||
"RTLSXcCc",
|
||||
ret, "text/html", X_USER_AGENT);
|
||||
ret, "text/html", &RespInstr, X_USER_AGENT);
|
||||
http_SendMessage(info, &timeout, "b",
|
||||
headers.buf, headers.length);
|
||||
break;
|
||||
|
@@ -387,7 +387,7 @@ static int parse_hostport(
|
||||
|
||||
ret = getaddrinfo(srvname, NULL, &hints, &res0);
|
||||
if (ret == 0) {
|
||||
for (res = res0; res && !ret; res = res->ai_next) {
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
switch (res->ai_family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
@@ -395,12 +395,10 @@ static int parse_hostport(
|
||||
memcpy(&out->IPaddress,
|
||||
res->ai_addr,
|
||||
res->ai_addrlen);
|
||||
ret=1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
found:
|
||||
freeaddrinfo(res0);
|
||||
if (res == NULL)
|
||||
/* Didn't find an AF_INET or AF_INET6 address. */
|
||||
@@ -512,68 +510,81 @@ int remove_escaped_chars(INOUT char *in, INOUT size_t *size)
|
||||
}
|
||||
|
||||
|
||||
int remove_dots(char *in, size_t size)
|
||||
static UPNP_INLINE int is_end_path(char c) {
|
||||
switch (c) {
|
||||
case '?':
|
||||
case '#':
|
||||
case '\0':
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This function directly implements the "Remove Dot Segments"
|
||||
* algorithm described in RFC 3986 section 5.2.4. */
|
||||
int remove_dots(char *buf, size_t size)
|
||||
{
|
||||
char *copyTo = in;
|
||||
char *copyFrom = in;
|
||||
char *max = in + size;
|
||||
char **Segments = NULL;
|
||||
int lastSegment = -1;
|
||||
char *in = buf;
|
||||
char *out = buf;
|
||||
char *max = buf + size;
|
||||
|
||||
Segments = malloc( sizeof( char * ) * size );
|
||||
while (!is_end_path(in[0])) {
|
||||
assert (buf <= out);
|
||||
assert (out <= in);
|
||||
assert (in < max);
|
||||
|
||||
if( Segments == NULL )
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
|
||||
Segments[0] = NULL;
|
||||
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
||||
"REMOVE_DOTS: before: %s\n", in );
|
||||
while( ( copyFrom < max ) && ( *copyFrom != '?' )
|
||||
&& ( *copyFrom != '#' ) ) {
|
||||
|
||||
if( ( ( *copyFrom ) == '.' )
|
||||
&& ( ( copyFrom == in ) || ( *( copyFrom - 1 ) == '/' ) ) ) {
|
||||
if( ( copyFrom + 1 == max )
|
||||
|| ( *( copyFrom + 1 ) == '/' ) ) {
|
||||
|
||||
copyFrom += 2;
|
||||
continue;
|
||||
} else if( ( *( copyFrom + 1 ) == '.' )
|
||||
&& ( ( copyFrom + 2 == max )
|
||||
|| ( *( copyFrom + 2 ) == '/' ) ) ) {
|
||||
copyFrom += 3;
|
||||
|
||||
if( lastSegment > 0 ) {
|
||||
copyTo = Segments[--lastSegment];
|
||||
} else {
|
||||
free( Segments );
|
||||
/*TRACE("ERROR RESOLVING URL, ../ at ROOT"); */
|
||||
return UPNP_E_INVALID_URL;
|
||||
}
|
||||
continue;
|
||||
/* case 2.A: */
|
||||
if (strncmp(in, "./", 2) == 0) {
|
||||
in += 2;
|
||||
} else if (strncmp(in, "../", 3) == 0) {
|
||||
in += 3;
|
||||
/* case 2.B: */
|
||||
} else if (strncmp(in, "/./", 3) == 0) {
|
||||
in += 2;
|
||||
} else if (strncmp(in, "/.", 2) == 0 && is_end_path(in[2])) {
|
||||
in += 1;
|
||||
in[0] = '/';
|
||||
/* case 2.C: */
|
||||
} else if (strncmp(in, "/../", 4) == 0 || (strncmp(in, "/..", 3) == 0 && is_end_path(in[3]))) {
|
||||
/* Make the next character in the input buffer a '/': */
|
||||
if (is_end_path(in[3])) { /* terminating "/.." case */
|
||||
in += 2;
|
||||
in[0] = '/';
|
||||
} else { /* "/../" prefix case */
|
||||
in += 3;
|
||||
}
|
||||
}
|
||||
|
||||
if( ( *copyFrom ) == '/' ) {
|
||||
|
||||
lastSegment++;
|
||||
Segments[lastSegment] = copyTo + 1;
|
||||
}
|
||||
( *copyTo ) = ( *copyFrom );
|
||||
copyTo++;
|
||||
copyFrom++;
|
||||
}
|
||||
if( copyFrom < max ) {
|
||||
while( copyFrom < max ) {
|
||||
( *copyTo ) = ( *copyFrom );
|
||||
copyTo++;
|
||||
copyFrom++;
|
||||
/* Trim the last component from the output buffer, or empty it. */
|
||||
while (buf < out)
|
||||
if (*--out == '/')
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
if (out < in)
|
||||
out[0] = '\0';
|
||||
#endif
|
||||
/* case 2.D: */
|
||||
} else if (strncmp(in, ".", 1) == 0 && is_end_path(in[1])) {
|
||||
in += 1;
|
||||
} else if (strncmp(in, "..", 2) == 0 && is_end_path(in[2])) {
|
||||
in += 2;
|
||||
/* case 2.E */
|
||||
} else {
|
||||
/* move initial '/' character (if any) */
|
||||
if (in[0] == '/')
|
||||
*out++ = *in++;
|
||||
/* move first segment up to, but not including, the next '/' character */
|
||||
while (in < max && in[0] != '/' && !is_end_path(in[0]))
|
||||
*out++ = *in++;
|
||||
#ifdef DEBUG
|
||||
if (out < in)
|
||||
out[0] = '\0';
|
||||
#endif
|
||||
}
|
||||
}
|
||||
( *copyTo ) = 0;
|
||||
free( Segments );
|
||||
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
||||
"REMOVE_DOTS: after: %s\n", in );
|
||||
while (in < max)
|
||||
*out++ = *in++;
|
||||
if (out < max)
|
||||
out[0] = '\0';
|
||||
return UPNP_E_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -582,115 +593,113 @@ char *resolve_rel_url(char *base_url, char *rel_url)
|
||||
{
|
||||
uri_type base;
|
||||
uri_type rel;
|
||||
int rv;
|
||||
|
||||
size_t i = (size_t)0;
|
||||
char *finger = NULL;
|
||||
|
||||
char *last_slash = NULL;
|
||||
|
||||
char *out = NULL;
|
||||
|
||||
if( base_url && rel_url ) {
|
||||
out =
|
||||
( char * )malloc( strlen( base_url ) + strlen( rel_url ) + (size_t)2 );
|
||||
} else {
|
||||
if( rel_url )
|
||||
return strdup( rel_url );
|
||||
else
|
||||
if (!base_url) {
|
||||
if (!rel_url)
|
||||
return NULL;
|
||||
return strdup(rel_url);
|
||||
}
|
||||
|
||||
if( out == NULL ) {
|
||||
size_t len_rel = strlen(rel_url);
|
||||
if (parse_uri(rel_url, len_rel, &rel) != HTTP_SUCCESS)
|
||||
return NULL;
|
||||
if (rel.type == (enum uriType)ABSOLUTE)
|
||||
return strdup(rel_url);
|
||||
|
||||
size_t len_base = strlen(base_url);
|
||||
if ((parse_uri(base_url, len_base, &base) != HTTP_SUCCESS)
|
||||
|| (base.type != (enum uriType)ABSOLUTE))
|
||||
return NULL;
|
||||
if (len_rel == (size_t)0)
|
||||
return strdup(base_url);
|
||||
|
||||
size_t len = len_base + len_rel + (size_t)2;
|
||||
char *out = (char *)malloc(len);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
memset(out, 0, len);
|
||||
char *out_finger = out;
|
||||
|
||||
/* scheme */
|
||||
rv = snprintf(out_finger, len, "%.*s:", (int)base.scheme.size, base.scheme.buff);
|
||||
if (rv < 0 || rv >= len)
|
||||
goto error;
|
||||
out_finger += rv;
|
||||
len -= rv;
|
||||
|
||||
/* authority */
|
||||
if (rel.hostport.text.size > (size_t)0) {
|
||||
rv = snprintf(out_finger, len, "%s", rel_url);
|
||||
if (rv < 0 || rv >= len)
|
||||
goto error;
|
||||
return out;
|
||||
}
|
||||
if (base.hostport.text.size > (size_t)0) {
|
||||
rv = snprintf(out_finger, len, "//%.*s", (int)base.hostport.text.size, base.hostport.text.buff);
|
||||
if (rv < 0 || rv >= len)
|
||||
goto error;
|
||||
out_finger += rv;
|
||||
len -= rv;
|
||||
}
|
||||
memset( out, 0, strlen( base_url ) + strlen( rel_url ) + (size_t)2 );
|
||||
|
||||
if( ( parse_uri( rel_url, strlen( rel_url ), &rel ) ) == HTTP_SUCCESS ) {
|
||||
|
||||
if( rel.type == ( enum uriType) ABSOLUTE ) {
|
||||
|
||||
strncpy( out, rel_url, strlen ( rel_url ) );
|
||||
} else {
|
||||
|
||||
if( ( parse_uri( base_url, strlen( base_url ), &base ) ==
|
||||
HTTP_SUCCESS )
|
||||
&& ( base.type == ( enum uriType ) ABSOLUTE ) ) {
|
||||
|
||||
if( strlen( rel_url ) == (size_t)0 ) {
|
||||
strncpy( out, base_url, strlen ( base_url ) );
|
||||
} else {
|
||||
char *out_finger = out;
|
||||
assert( base.scheme.size + (size_t)1 /* ':' */ <= strlen ( base_url ) );
|
||||
memcpy( out, base.scheme.buff, base.scheme.size );
|
||||
out_finger += base.scheme.size;
|
||||
( *out_finger ) = ':';
|
||||
out_finger++;
|
||||
|
||||
if( rel.hostport.text.size > (size_t)0 ) {
|
||||
snprintf( out_finger, strlen( rel_url ) + (size_t)1,
|
||||
"%s", rel_url );
|
||||
} else {
|
||||
if( base.hostport.text.size > (size_t)0 ) {
|
||||
assert( base.scheme.size + (size_t)1
|
||||
+ base.hostport.text.size + (size_t)2 /* "//" */ <= strlen ( base_url ) );
|
||||
memcpy( out_finger, "//", (size_t)2 );
|
||||
out_finger += 2;
|
||||
memcpy( out_finger, base.hostport.text.buff,
|
||||
base.hostport.text.size );
|
||||
out_finger += base.hostport.text.size;
|
||||
}
|
||||
|
||||
if( rel.path_type == ( enum pathType ) ABS_PATH ) {
|
||||
strncpy( out_finger, rel_url, strlen ( rel_url ) );
|
||||
|
||||
} else {
|
||||
char temp_path = '/';
|
||||
|
||||
if( base.pathquery.size == (size_t)0 ) {
|
||||
base.pathquery.size = (size_t)1;
|
||||
base.pathquery.buff = &temp_path;
|
||||
}
|
||||
|
||||
assert( base.scheme.size + (size_t)1 + base.hostport.text.size + (size_t)2
|
||||
+ base.pathquery.size <= strlen ( base_url ) + (size_t)1 /* temp_path */);
|
||||
finger = out_finger;
|
||||
last_slash = finger;
|
||||
i = (size_t)0;
|
||||
while( ( i < base.pathquery.size ) &&
|
||||
( base.pathquery.buff[i] != '?' ) ) {
|
||||
( *finger ) = base.pathquery.buff[i];
|
||||
if( base.pathquery.buff[i] == '/' )
|
||||
last_slash = finger + 1;
|
||||
i++;
|
||||
finger++;
|
||||
|
||||
}
|
||||
strncpy( last_slash, rel_url, strlen ( rel_url ) );
|
||||
if( remove_dots( out_finger,
|
||||
strlen( out_finger ) ) !=
|
||||
UPNP_E_SUCCESS ) {
|
||||
free(out);
|
||||
/* free(rel_url); */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
free(out);
|
||||
/* free(rel_url); */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* path */
|
||||
char *path = out_finger;
|
||||
if (rel.path_type == (enum pathType)ABS_PATH) {
|
||||
rv = snprintf(out_finger, len, "%s", rel_url);
|
||||
} else if (base.pathquery.size == (size_t)0) {
|
||||
rv = snprintf(out_finger, len, "/%s", rel_url);
|
||||
} else {
|
||||
free(out);
|
||||
/* free(rel_url); */
|
||||
return NULL;
|
||||
}
|
||||
if (rel.pathquery.size == (size_t)0) {
|
||||
rv = snprintf(out_finger, len, "%.*s", (int)base.pathquery.size, base.pathquery.buff);
|
||||
} else {
|
||||
if (len < base.pathquery.size)
|
||||
goto error;
|
||||
size_t i = (size_t)0, prefix = (size_t)1;
|
||||
while (i < base.pathquery.size) {
|
||||
out_finger[i] = base.pathquery.buff[i];
|
||||
switch (base.pathquery.buff[i++]) {
|
||||
case '/':
|
||||
prefix = i;
|
||||
/* fall-through */
|
||||
default:
|
||||
continue;
|
||||
case '?': /* query */
|
||||
if (rel.pathquery.buff[0] == '?')
|
||||
prefix = --i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
out_finger += prefix;
|
||||
len -= prefix;
|
||||
rv = snprintf(out_finger, len, "%.*s", (int)rel.pathquery.size, rel.pathquery.buff);
|
||||
}
|
||||
if (rv < 0 || rv >= len)
|
||||
goto error;
|
||||
out_finger += rv;
|
||||
len -= rv;
|
||||
|
||||
/* fragment */
|
||||
if (rel.fragment.size > (size_t)0)
|
||||
rv = snprintf(out_finger, len, "#%.*s", (int)rel.fragment.size, rel.fragment.buff);
|
||||
else if (base.fragment.size > (size_t)0)
|
||||
rv = snprintf(out_finger, len, "#%.*s", (int)base.fragment.size, base.fragment.buff);
|
||||
else
|
||||
rv = 0;
|
||||
}
|
||||
if (rv < 0 || rv >= len)
|
||||
goto error;
|
||||
out_finger += rv;
|
||||
len -= rv;
|
||||
|
||||
if (remove_dots(path, out_finger - path) != UPNP_E_SUCCESS)
|
||||
goto error;
|
||||
|
||||
/* free(rel_url); */
|
||||
return out;
|
||||
|
||||
error:
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -301,15 +301,16 @@ FindServiceEventURLPath( service_table * table,
|
||||
|
||||
if( ( table )
|
||||
&&
|
||||
( parse_uri
|
||||
( eventURLPath, strlen( eventURLPath ), &parsed_url_in ) ) ) {
|
||||
( parse_uri( eventURLPath,
|
||||
strlen( eventURLPath ),
|
||||
&parsed_url_in ) == HTTP_SUCCESS ) ) {
|
||||
|
||||
finger = table->serviceList;
|
||||
while( finger ) {
|
||||
if( finger->eventURL )
|
||||
if( ( parse_uri
|
||||
( finger->eventURL, strlen( finger->eventURL ),
|
||||
&parsed_url ) ) ) {
|
||||
&parsed_url ) == HTTP_SUCCESS ) ) {
|
||||
|
||||
if( !token_cmp
|
||||
( &parsed_url.pathquery,
|
||||
@@ -354,13 +355,13 @@ FindServiceControlURLPath( service_table * table,
|
||||
&&
|
||||
( parse_uri
|
||||
( controlURLPath, strlen( controlURLPath ),
|
||||
&parsed_url_in ) ) ) {
|
||||
&parsed_url_in ) == HTTP_SUCCESS ) ) {
|
||||
finger = table->serviceList;
|
||||
while( finger ) {
|
||||
if( finger->controlURL )
|
||||
if( ( parse_uri
|
||||
( finger->controlURL, strlen( finger->controlURL ),
|
||||
&parsed_url ) ) ) {
|
||||
&parsed_url ) == HTTP_SUCCESS) ) {
|
||||
if( !token_cmp
|
||||
( &parsed_url.pathquery,
|
||||
&parsed_url_in.pathquery ) )
|
||||
|
@@ -79,6 +79,10 @@
|
||||
#define HTTP_SERVICE_UNAVAILABLE 503
|
||||
#define HTTP_GATEWAY_TIMEOUT 504
|
||||
#define HTTP_HTTP_VERSION_NOT_SUPPORTED 505
|
||||
#define HTTP_VARIANT_ALSO_NEGOTIATES 506
|
||||
#define HTTP_INSUFFICIENT_STORAGE 507
|
||||
#define HTTP_LOOP_DETECTED 508
|
||||
#define HTTP_NOT_EXTENDED 510
|
||||
|
||||
/* HTTP lib error codes */
|
||||
|
||||
|
@@ -455,7 +455,7 @@ get_response_value( IN http_message_t * hmsg,
|
||||
if (!temp_str)
|
||||
goto error_handler;
|
||||
*upnp_error_code = atoi(temp_str);
|
||||
if (*upnp_error_code < 400) {
|
||||
if (*upnp_error_code > 400) {
|
||||
err_code = *upnp_error_code;
|
||||
goto error_handler; /* bad SOAP error code */
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -291,8 +291,9 @@ void ssdp_handle_ctrlpt_msg(http_message_t *hmsg, struct sockaddr_storage *dest_
|
||||
TPJobSetFreeFunction(&job,
|
||||
(free_routine)
|
||||
free);
|
||||
ThreadPoolAdd(&gRecvThreadPool, &job,
|
||||
NULL);
|
||||
if (ThreadPoolAdd(&gRecvThreadPool, &job, NULL) != 0) {
|
||||
free(threadData);
|
||||
}
|
||||
}
|
||||
}
|
||||
node = ListNext(&ctrlpt_info->SsdpSearchList, node);
|
||||
|
@@ -814,7 +814,7 @@ static int create_ssdp_sock_v4(
|
||||
ret = UPNP_E_SOCKET_ERROR;
|
||||
goto error_handler;
|
||||
}
|
||||
#if defined(BSD) || defined(__OSX__) || defined(__APPLE__)
|
||||
#if (defined(BSD) && !defined(__GNU__)) || defined(__OSX__) || defined(__APPLE__)
|
||||
onOff = 1;
|
||||
ret = setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEPORT,
|
||||
(char *)&onOff, sizeof(onOff));
|
||||
@@ -956,7 +956,7 @@ static int create_ssdp_sock_v6(
|
||||
ret = UPNP_E_SOCKET_ERROR;
|
||||
goto error_handler;
|
||||
}
|
||||
#if defined(BSD) || defined(__OSX__) || defined(__APPLE__)
|
||||
#if (defined(BSD) && !defined(__GNU__)) || defined(__OSX__) || defined(__APPLE__)
|
||||
onOff = 1;
|
||||
ret = setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEPORT,
|
||||
(char *)&onOff, sizeof(onOff));
|
||||
@@ -1069,7 +1069,7 @@ static int create_ssdp_sock_v6_ula_gua(
|
||||
ret = UPNP_E_SOCKET_ERROR;
|
||||
goto error_handler;
|
||||
}
|
||||
#if defined(BSD) || defined(__OSX__) || defined(__APPLE__)
|
||||
#if (defined(BSD) && !defined(__GNU__)) || defined(__OSX__) || defined(__APPLE__)
|
||||
onOff = 1;
|
||||
ret = setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEPORT,
|
||||
(char *)&onOff, sizeof(onOff));
|
||||
|
@@ -143,15 +143,12 @@ static UPNP_INLINE int calc_alias(
|
||||
aliasPtr = alias + 1;
|
||||
else
|
||||
aliasPtr = alias;
|
||||
new_alias_len = root_len + strlen(temp_str) + strlen(aliasPtr);
|
||||
alias_temp = malloc(new_alias_len + (size_t)1);
|
||||
new_alias_len = root_len + strlen(temp_str) + strlen(aliasPtr) + (size_t)1;
|
||||
alias_temp = malloc(new_alias_len);
|
||||
if (alias_temp == NULL)
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
memset(alias_temp, 0, new_alias_len + (size_t)1);
|
||||
strncpy(alias_temp, rootPath, root_len);
|
||||
alias_temp[root_len] = '\0';
|
||||
strncat(alias_temp, temp_str, strlen(temp_str));
|
||||
strncat(alias_temp, aliasPtr, strlen(aliasPtr));
|
||||
memset(alias_temp, 0, new_alias_len);
|
||||
snprintf(alias_temp, new_alias_len, "%s%s%s", rootPath, temp_str, aliasPtr);
|
||||
|
||||
*newAlias = alias_temp;
|
||||
return UPNP_E_SUCCESS;
|
||||
@@ -186,14 +183,10 @@ static UPNP_INLINE int calc_descURL(
|
||||
assert(ipPortStr != NULL && strlen(ipPortStr) > 0);
|
||||
assert(alias != NULL && strlen(alias) > 0);
|
||||
|
||||
len = strlen(http_scheme) + strlen(ipPortStr) + strlen(alias);
|
||||
if (len > ((size_t)LINE_SIZE - (size_t)1))
|
||||
len = strlen(http_scheme) + strlen(ipPortStr) + strlen(alias) + (size_t)1;
|
||||
if (len > (size_t)LINE_SIZE)
|
||||
return UPNP_E_URL_TOO_BIG;
|
||||
strncpy(descURL, http_scheme, strlen(http_scheme));
|
||||
descURL[strlen(http_scheme)] = '\0';
|
||||
strncat(descURL, ipPortStr, strlen(ipPortStr));
|
||||
strncat(descURL, alias, strlen(alias));
|
||||
descURL[len] = '\0';
|
||||
snprintf(descURL, len, "%s%s%s", http_scheme, ipPortStr, alias);
|
||||
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
|
||||
"desc url: %s\n", descURL);
|
||||
|
||||
@@ -267,6 +260,7 @@ static int config_description_doc(
|
||||
err_code =
|
||||
ixmlNode_appendChild(rootNode, (IXML_Node *) element);
|
||||
if (err_code != IXML_SUCCESS) {
|
||||
err_code = UPNP_E_INVALID_DESC;
|
||||
goto error_handler;
|
||||
}
|
||||
textNode =
|
||||
@@ -277,6 +271,7 @@ static int config_description_doc(
|
||||
err_code =
|
||||
ixmlNode_appendChild((IXML_Node *) element, textNode);
|
||||
if (err_code != IXML_SUCCESS) {
|
||||
err_code = UPNP_E_INTERNAL_ERROR;
|
||||
goto error_handler;
|
||||
}
|
||||
} else {
|
||||
@@ -327,6 +322,7 @@ static int config_description_doc(
|
||||
}
|
||||
err_code = ixmlNode_setNodeValue(textNode, url_str.buf);
|
||||
if (err_code != IXML_SUCCESS) {
|
||||
err_code = UPNP_E_OUTOF_MEMORY;
|
||||
goto error_handler;
|
||||
}
|
||||
}
|
||||
|
131
upnp/test/test_url.c
Normal file
131
upnp/test/test_url.c
Normal file
@@ -0,0 +1,131 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "upnp.h"
|
||||
#include "upnptools.h"
|
||||
|
||||
struct test {
|
||||
const char *base;
|
||||
const char *rel;
|
||||
const char *expect;
|
||||
int line;
|
||||
int error;
|
||||
};
|
||||
#define TEST(BaseURL, RelURL, expect, ...) {BaseURL, RelURL, expect, __LINE__, ##__VA_ARGS__}
|
||||
|
||||
static int
|
||||
result(const struct test *test)
|
||||
{
|
||||
char *absurl = NULL;
|
||||
int ret = 0;
|
||||
|
||||
ret = UpnpResolveURL2(test->base, test->rel, &absurl);
|
||||
if (ret == test->error && (test->expect == NULL || strcmp(test->expect, absurl) == 0)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
printf("%s:%d: '%s' | '%s' -> '%s' != '%s' (%d)\n", __FILE__, test->line, test->base, test->rel, absurl, test->expect, ret);
|
||||
ret = 1;
|
||||
}
|
||||
free(absurl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The URLs must be resolvale! */
|
||||
static const char ABS_URL1[] = "http://www.libupnp.org/path1/";
|
||||
static const char ABS_URL2[] = "http://www.libupnp.org/path1/path1";
|
||||
static const char ABS_URL3[] = "http://localhost/path1/";
|
||||
static const char ABS_URL4[] = "http://127.0.0.1/path1/";
|
||||
static const char ABS_URL5[] = "http://127.0.0.1:6544/path1/";
|
||||
static const char ABS_URL6[] = "http://[::1]:6544/path1/";
|
||||
|
||||
static const char REL_URL1[] = "//localhost/path2";
|
||||
static const char REL_URL2[] = "/path3";
|
||||
static const char REL_URL3[] = "path4";
|
||||
static const char REL_URL4[] = "../path5";
|
||||
static const char REL_URL5[] = "?query1";
|
||||
static const char REL_URL6[] = "#frag1";
|
||||
|
||||
static const char ABS_RFC[] = "http://localhost/b/c/d;p?q";
|
||||
// s,\<a\>,localhost,
|
||||
// s,//g\>,//127.0.0.1,
|
||||
|
||||
static const struct test RFC3986[] = {
|
||||
// Errors
|
||||
TEST(NULL, NULL, NULL, UPNP_E_INVALID_PARAM),
|
||||
TEST(ABS_URL1, NULL, NULL, UPNP_E_INVALID_PARAM),
|
||||
TEST("foo", "bar", NULL, UPNP_E_INVALID_URL),
|
||||
// Custom
|
||||
TEST(NULL, ABS_URL1, ABS_URL1),
|
||||
TEST(ABS_URL1, ABS_URL2, ABS_URL2),
|
||||
TEST(ABS_URL1, "", ABS_URL1),
|
||||
TEST(ABS_URL1, REL_URL1, "http://localhost/path2"),
|
||||
TEST(ABS_URL2, REL_URL1, "http://localhost/path2"),
|
||||
TEST(ABS_URL1, REL_URL2, "http://www.libupnp.org/path3"),
|
||||
TEST(ABS_URL2, REL_URL2, "http://www.libupnp.org/path3"),
|
||||
TEST(ABS_URL1, REL_URL3, "http://www.libupnp.org/path1/path4"),
|
||||
TEST(ABS_URL2, REL_URL3, "http://www.libupnp.org/path1/path4"),
|
||||
TEST(ABS_URL1, REL_URL4, "http://www.libupnp.org/path5"),
|
||||
TEST(ABS_URL2, REL_URL4, "http://www.libupnp.org/path5"),
|
||||
TEST(ABS_URL1, REL_URL6, "http://www.libupnp.org/path1/#frag1"),
|
||||
TEST(ABS_URL2, REL_URL6, "http://www.libupnp.org/path1/path1#frag1"),
|
||||
TEST("http://127.0.0.1:6544/getDeviceDesc", "CDS_Event", "http://127.0.0.1:6544/CDS_Event"),
|
||||
// <http://tools.ietf.org/html/rfc3986#section-5.4.1> Normal Examples
|
||||
TEST(ABS_RFC, "g:h", "g:h"),
|
||||
TEST(ABS_RFC, "g", "http://localhost/b/c/g"),
|
||||
TEST(ABS_RFC, "./g", "http://localhost/b/c/g"),
|
||||
TEST(ABS_RFC, "g/", "http://localhost/b/c/g/"),
|
||||
TEST(ABS_RFC, "/g", "http://localhost/g"),
|
||||
TEST(ABS_RFC, "//127.0.0.1", "http://127.0.0.1"),
|
||||
TEST(ABS_RFC, "?y", "http://localhost/b/c/d;p?y"),
|
||||
TEST(ABS_RFC, "g?y", "http://localhost/b/c/g?y"),
|
||||
TEST(ABS_RFC, "#s", "http://localhost/b/c/d;p?q#s"),
|
||||
TEST(ABS_RFC, "g#s", "http://localhost/b/c/g#s"),
|
||||
TEST(ABS_RFC, "g?y#s", "http://localhost/b/c/g?y#s"),
|
||||
TEST(ABS_RFC, ";x", "http://localhost/b/c/;x"),
|
||||
TEST(ABS_RFC, "g;x", "http://localhost/b/c/g;x"),
|
||||
TEST(ABS_RFC, "g;x?y#s", "http://localhost/b/c/g;x?y#s"),
|
||||
TEST(ABS_RFC, "", "http://localhost/b/c/d;p?q"),
|
||||
TEST(ABS_RFC, ".", "http://localhost/b/c/"),
|
||||
TEST(ABS_RFC, "./", "http://localhost/b/c/"),
|
||||
TEST(ABS_RFC, "..", "http://localhost/b/"),
|
||||
TEST(ABS_RFC, "../", "http://localhost/b/"),
|
||||
TEST(ABS_RFC, "../g", "http://localhost/b/g"),
|
||||
TEST(ABS_RFC, "../..", "http://localhost/"),
|
||||
TEST(ABS_RFC, "../../", "http://localhost/"),
|
||||
TEST(ABS_RFC, "../../g", "http://localhost/g"),
|
||||
// <http://tools.ietf.org/html/rfc3986#section-5.4.2> Abnormal Examples
|
||||
TEST(ABS_RFC, "../../../g", "http://localhost/g"),
|
||||
TEST(ABS_RFC, "../../../../g", "http://localhost/g"),
|
||||
TEST(ABS_RFC, "/./g", "http://localhost/g"),
|
||||
TEST(ABS_RFC, "/../g", "http://localhost/g"),
|
||||
TEST(ABS_RFC, "g.", "http://localhost/b/c/g."),
|
||||
TEST(ABS_RFC, ".g", "http://localhost/b/c/.g"),
|
||||
TEST(ABS_RFC, "g..", "http://localhost/b/c/g.."),
|
||||
TEST(ABS_RFC, "..g", "http://localhost/b/c/..g"),
|
||||
TEST(ABS_RFC, "./../g", "http://localhost/b/g"),
|
||||
TEST(ABS_RFC, "./g/.", "http://localhost/b/c/g/"),
|
||||
TEST(ABS_RFC, "g/./h", "http://localhost/b/c/g/h"),
|
||||
TEST(ABS_RFC, "g/../h", "http://localhost/b/c/h"),
|
||||
TEST(ABS_RFC, "g;x=1/./y", "http://localhost/b/c/g;x=1/y"),
|
||||
TEST(ABS_RFC, "g;x=1/../y", "http://localhost/b/c/y"),
|
||||
TEST(ABS_RFC, "g?y/./x", "http://localhost/b/c/g?y/./x"),
|
||||
TEST(ABS_RFC, "g?y/../x", "http://localhost/b/c/g?y/../x"),
|
||||
TEST(ABS_RFC, "g#s/./x", "http://localhost/b/c/g#s/./x"),
|
||||
TEST(ABS_RFC, "g#s/../x", "http://localhost/b/c/g#s/../x"),
|
||||
TEST(ABS_RFC, "http:g", "http:g"),
|
||||
};
|
||||
#define ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
|
||||
|
||||
int
|
||||
main (int argc, char* argv[])
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(RFC3986); i++)
|
||||
ret += result(&RFC3986[i]);
|
||||
|
||||
exit (ret ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// gcc -o url-test -g url-test.c -I ixml/inc -I threadutil/inc -I upnp/inc upnp/.libs/libupnp.a -L ixml/.libs -lixml -L threadutil/.libs -lthreadutil -lpthread
|
Reference in New Issue
Block a user