I am building a web service for ONVIF camera using gSoap.
I have generated the header and the source files using the core wdsl provided by ONVIF at https://www.onvif.org/profiles/specifications/.
However, every time i make a request from the client i get the below error in the function soap_begin_serve(soap):
SOAP 1.2 fault SOAP-ENV:MustUnderstand[no subcode]
"The data in element 'Security' must be understood but cannot be processed"
What does the above error means and how can i fix it?
EDIT: This is what i receive at the camera side:
POST / HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver10/device/wsdl/GetSystemDateAndTime"
Host: localhost:8090
Content-Length: 261
Accept-Encoding: gzip, deflate
Connection: Close
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetSystemDateAndTime xmlns="http://www.onvif.org/ver10/device/wsdl"/></s:Body></s:Envelope>POST / HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver10/device/wsdl/GetScopes"
Host: localhost:8090
Content-Length: 905
Accept-Encoding: gzip, deflate
Connection: Close
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Header><Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><UsernameToken><Username>admin</Username><Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">WFz21zL8rch8LRoxAPzgHRMBbr0=</Password><Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">9y79ka0xD02oCIw6GAoIPwEAAAAAAA==</Nonce><Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2017-05-21T08:15:58.902Z</Created></UsernameToken></Security></s:Header><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><GetScopes xmlns="http://www.onvif.org/ver10/device/wsdl"/></s:Body></s:Envelope>
SOAP 1.2 fault SOAP-ENV:MustUnderstand[no subcode]
"The data in element 'Security' must be understood but cannot be processed"
This means that you will need to enable WS-Security to authenticate:
add #import "wsse.h" to the .h header file (aka. service and data binding "interface file") for soapcpp2 to process.
in your source code, #include "plugin/wsseapi.h"
in your source code, provide the user credentials before sending the request with soap_wsse_add_UsernameTokenDigest(soap, NULL, "username", "password");
compile the source code with compiler flag -DWITH_OPENSSL and compile your application code base together with plugin/wsseapi.c, plugin/smdevp.c, and plugin/mecevp.c (the plugin directory is in the gSOAP distro path), and of course also compile stdsoap2.c or stdsoap2.cpp and other generated files;
link with OpenSSL -lssl -lcrypto, and perhaps -lz if compression is desired;
when using the full WS-Security plugin capabilities with gSOAP (digital signature and/or encryption), you should compile all your source code with compiler option -DWITH_OPENSSL -DWITH_DOM -DWITH_GZIP and also compile dom.c or dom.cpp together with your code.
See also the WS-Security plugin for gSOAP.
Hope this helps.
Related
I have been upgrading some Python 2 scripts to Python 3. I used 2to3 to refactor the code. Running with python3, I get an exception. I was able to reproduce the problems with just three lines of code;
import jsonrpclib
p = jsonrpclib.Server("http://r195/cgi-bin/streamscape_api")
print(p.nodeid())
With python2, it works:
$ python rpc.py
[u'3011']
When I run the exact same code with Python3, I get this exception:
$ python3 rpc.py
Traceback (most recent call last):
File "rpc.py", line 6, in <module>
print(p.nodeid())
File "/home/kory/.local/lib/python3.8/site-packages/jsonrpclib/jsonrpc.py", line 265, in __call__
return self.__send(self.__name, kwargs)
File "/home/kory/.local/lib/python3.8/site-packages/jsonrpclib/jsonrpc.py", line 212, in _request
response = self._run_request(request)
File "/home/kory/.local/lib/python3.8/site-packages/jsonrpclib/jsonrpc.py", line 226, in _run_request
response = self.__transport.request(
File "/usr/lib/python3.8/xmlrpc/client.py", line 1153, in request
return self.single_request(host, handler, request_body, verbose)
File "/usr/lib/python3.8/xmlrpc/client.py", line 1183, in single_request
raise ProtocolError(
xmlrpc.client.ProtocolError: <ProtocolError for r195/cgi-bin/streamscape_api: 400 Bad Request>
Using WireShark, I captured the traffic between the python script and the webserver. The only difference was tje header. With python2, thid is the header sent to the webserver;
Host: r195
Accept-Encoding: gzip
User-Agent: jsonrpclib/0.1 (Python 2.7.18)
Content-Type: application/json-rpc
With python3, the header is:
Host: r195
Accept-Encoding: gzip
Content-Type: text/xml
User-Agent: jsonrpclib/0.1 (Python 3.8.10)
Content-Type: application/json-rpc
Notice that python3, sends two "Content-Type" headers. Using curl
to build a request packet the headers, the problem is the "Content-Type: text/xml". Sending the request with curl without that content type, works correctly.
Just to be sure, as a test, I commented out this line from xmlrpc/client.py, and the script now works with python3. But commenting out that line is not a viable solution. I believe the webserver is running lighttpd 1.4.54.
Part of the issue is due to the way the xmlrpc.py has changed from python2 to python3. the send_content() used to be the one adding content-type header and send_request would just send the request in 2.
In 3, xmlrpc adds content-type in send_request() which is semantically incorrect. So when jsonrpclib overloads send_content() it adds the extra content-type header.
This project: https://github.com/tcalmant/jsonrpclib/tree/master/jsonrpclib corrects this by overloading send_request() as well and does not add the content-type header, which is correctly done in the overloaded send_content. So using this would fix this issue. However the underlying issue of why lighttpd fails when there are repeated content-type is weird. If there is no answer, we can go ahead and ignore, since most clients will not do this.
What I would like to know is that is this a python3 jdonrpclib bug or a lighthttpd bug?
What I would like to know is that is this a python3 jdonrpclib bug or a lighthttpd bug?
Sending two (or more) different Content-Type headers with a request is definitely a bug in the python library/libraries interaction.
However the underlying issue of why lighttpd fails when there are repeated content-type is weird.
No, it is not weird. lighttpd intentionally rejects duplicated Content-Type in the request, and has done so since lighttpd 1.3.12 (released in 2005). Those duplicated Content-Type headers conflict with one another in your invalid request.
You can set lighttpd.conf debug.log-request-header-on-error = "enable" and lighttpd will report the following in the lighttpd error log for the invalid request: "duplicate Content-Type header -> 400"
[Edit] For reference:
RFC7231 Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
RFC 7231 Appendix D. Collected ABNF defines Content-Type = media-type, allowing a single media-type, not a variable number. As a consequence, duplicated Content-Type headers are not permitted by the spec.
I'm trying to upload a custom logo using CMD_API_SKINS
Here is my full code using curl + bash:
#/bin/bash
# DA needs this path
mkdir -p /home/tmp
# Assume my logo file is already here:
default_logo_file_home="/home/tmp/logo.png"
# The logo file is set to nobody:nogroup
chown nobody:nogroup "${default_logo_file_home}"
## Setup query data for curl:
username="admin"
password="12321aa"
da_port="2222"
host_server="server.domain.com"
ssl="https"
skin_name="evolution"
command="CMD_API_SKINS"
data="action=upload_logo&file=${default_logo_file_home}&json=yes&name=${skin_name}&which=1"
method="POST"
curl --silent --request "${method}" --user "${username}":"${password}" --data "${data}" "${ssl}://${host_server}:${da_port}/${command}"
When debugging this API, I got an error like this:
text='An Error Occurred'
result='Cannot get mime-type for log<br>
It seems like DA is trying to parse and obtain the extension name for the file "logo.png" but it couldn't
Full error logs:
DirectAdmin 1.61.5
Accepting Connections on port 2222
Sockets::handshake - begin
Sockets::handshake - end
/CMD_API_SKINS
0: Accept: */*
1: Authorization: Basic bWF4aW93bng3OnhGVEVHe***jUSg/UTRTfVdHYW0+fWNURn5ATWN***HFbZGpMezlQZ***=
2: Content-Length: 75
3: Content-Type: application/x-www-form-urlencoded
4: Host: server.domain.com:2222
5: User-Agent: curl/7.75.0
Post string: action=upload_logo&file=/home/tmp/logo2.png&json=yes&name=evolution&which=2
auth.authenticated
User::deny_override:/CMD_API_SKINS: call_level=2, depth1: aborting due to do depth
User::deny_override:/CMD_DOMAIN: call_level=2, depth1: aborting due to do depth
User::deny_override:/CMD_DOMAIN: call_level=1, depth2: aborting due to do depth
Plugin::addHooks: start
Plugin::addHooks: end
Command::doCommand(/CMD_API_SKINS)
cannot get mime type for log
Dynamic(api=1, error=1):
text='An Error Occurred'
result='Cannot get mime-type for log<br>
'
Command::doCommand(/CMD_API_SKINS) : finished
Command::run: finished /CMD_API_SKINS
I also try to encode the query like this but still got the same error
default_logo_file_home="%2Fhome%2Ftmp%2Flogo%2Epng"
data="action=upload%5Flogo&file=${default_logo_file_home}&json=yes&name=${skin_name}&which=%31"
Is there any explanations what is going on here? Is it possible to upload a logo using this API ?
Ok, I found the trick which is not documented anywhere. The uploaded file need to have a random string append to it. So I changed this:
default_logo_file_home="/home/tmp/logo.png"
into this:
RANDOM_STR="EbYIES"
default_logo_file_home="/home/tmp/logo.png${RANDOM_STR}"
Now it's working perfectly
I have a link for a GitHub repository and I'm using github3 with Python in order to try and search for it.
Take this link for example:
https://github.com/GabrielGrimberg/OOP-Assignment1-UI
If you go to it, you will see that it redirects to
https://github.com/GabrielGrimberg/RuneScape-UI
And thus, I can't figure out how to construct a search query that will find this specific repo.
I've tried:
GabrielGrimberg/OOP-Assignment1-UI in:url
GabrielGrimberg/OOP-Assignment1-UI
GabrielGrimberg/OOP-Assignment1-UI in:full_name
According to Github blog if a repo is renamed the old address is redirected to new address!
We're happy to announce that starting today, we'll automatically redirect all requests for previous repository locations to their new home in these circumstances. There's nothing special you have to do. Just rename away and we'll take care of the rest.
Moreover you can check Gabriel Grimberg does not have any repo named "OOP-Assignment1-UI".
Corrected answer:
If we can first check repo details to make sure it exists/where it has moved!
Check out the following query:
curl -i https://github.com/GabrielGrimberg/OOP-Assignment1-UI
You can get the url where it moved from the header
HTTP/1.1 301 Moved Permanently
Server: GitHub.com
Date: Sun, 12 Feb 2017 18:19:25 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Status: 301 Moved Permanently
Cache-Control: no-cache
Vary: X-PJAX
Location: https://github.com/GabrielGrimberg/RuneScape-UI
X-UA-Compatible: IE=Edge,chrome=1
If the repo already existed there it would have given you the content instead of the header!
For example , try this:
curl -i https://github.com/GabrielGrimberg/RuneScape-UI
Basically you need to make a request yourself and check for the redirection if the first search provided no result.
def get_redirection(full_name):
try:
json_object = json.loads(urllib.request.urlopen('https://api.github.com/repos/{0}'.format(full_name)).read().decode('utf-8'))
except urllib.error.HTTPError:
return None
return json_object["full_name"] # Will return the new full-name of the project
I need to send audio message for a client. I'm using the API like in this link:
<?php
require_once('/path/to/twilio-php/Services/Twilio.php'); // Loads the library
$sid = "ACf2a000728962e9b8135bf456d89cfd7a";
$token = "{{ auth_token }}";
$client = new Services_Twilio($sid, $token);
$client->account->messages->sendMessage("+14158141829", "+15558675309", "Jenny please?! I love you <3", "http://www.example.com/love_words.wav");
The message does not get delivered and I don't get any error message. It works if I'm using text and/or image but not with audio.
How can I send an audio message with Twilio?
Try to set the correct MIME type header in the server where file is allocated
Please take a look at this URL
https://www.twilio.com/docs/api/rest/accepted-mime-types
If Content is invalid you will see in Twilio portal SMS/MMS logs the following:
Error: 12300 - Invalid Content-Type
For example:
curl -v -O http://www.schiffert.me/select1.wav
Returns:
Content-Type: audio/x-wav
which is invalid
But
curl -v -O http://www.schiffert.me/feedback.mp3
Returns:
Content-Type: audio/mpeg
I have this image from Filepicker.io: https://www.filepicker.io/api/file/9H-1AxgZTwqct8tjkmkZ
But when I open it in the browser, it will download the file directly, I thought that's because the response header or something, so I'm wondering how to proxy it so that I can view it in browser like other images, like this one : https://distilleryimage1.s3.amazonaws.com/84d490a4071811e285a622000a1d039f_5.jpg
curl -si https://www.filepicker.io/api/file/9H-1AxgZTwqct8tjkmkZ | head
HTTP/1.1 200 OK
Access-Control-Allow-Headers: CONTENT-TYPE, X-NO-STREAM
Access-Control-Allow-Methods: DELETE, GET, HEAD, POST, PUT
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 21600
Cache-Control: public, max-age=315360000, no-transform
Content-Disposition: attachment; filename="中秋福利.jpg"
Content-Type: image/jpeg
Date: Fri, 28 Sep 2012 08:21:45 GMT
Server: gunicorn/0.14.6
Content-Disposition is set to attachment. If you proxy it then remove that header altogether or set it to inline.
While vinayr's answer is correct, you can avoid using a proxy altogether by appending ?dl=false to the end of your FilePicker URI.
For example: https://www.filepicker.io/api/file/9H-1AxgZTwqct8tjkmkZ?dl=false
There are also a number of other in the FilePicker Documentation, particularly the "Working with FPUrls" section and the "Retrieving the file" and "Image Conversion" subsections.
Github uses https://github.com/atmos/camo to proxy images for SSL. You can try using it. You can mount it on your express app:
var camo = require('./node_modules/server.js') // you have to strip the server.listen(port) part
app.use('/proxy', camo)