This plugin is an API to download files and web content to the server and/or send commands using the HTTP protocol through other plugins.
It is not used to send files to clients. That is impossible.
This plugin will always keep itself up to date by automatically downloading the latest version whenever a new one is available.
This means that you as a developer can be relatively sure that the client has the correct version if your plugin requires possibly new functions.
This can be disabled by cvar.
You can also use this plugin to update your own plugin automatically. I suggest adding a version check first. Examples can be found below.
Remember that floats in PAWN are not 100% accurate so integers or strings should be used for checking if there is a new version available.
Also remember that for your plugin to be updated (downloaded) it has to compile without custom includes on this site. So any external functions has to be included inside the source of your plugin.
This can also be disabled by cvar.
Examples
GET, POST & Raw POST
Code:
#include <amxmodx>#include <httpx>public plugin_init(){register_plugin("HTTP:X GET, POST, Raw POST", "1.0", "[ --{-@ ]");
HTTPX_AddPostVar("This is a POST variable", "This is the POST value");
HTTPX_Download("digitaldecay.eu/posttest.php?This%20is%20a%20GET%20variable=This%20is%20the%20GET%20value", _, "Complete", _, _, REQUEST_POST);
HTTPX_AddPostVar("This is a POST variable", "This is the POST value");
HTTPX_Download("digitaldecay.eu/posttest2.php", _, "Complete", _, _, REQUEST_POST);
HTTPX_AddPostRaw("This data is 100% raw! I can write whatever I want! ()YDF)/Y^"PORKF_PSJUVYO U^"V¤OUMC¤O()U;^"=)#XI:");
HTTPX_Download("digitaldecay.eu/posttest2.php", _, "Complete", _, _, REQUEST_POST);
}public Complete(Index, Error){new Data[256];
while( HTTPX_GetData(Data, charsmax(Data)))server_print("%s", Data);
}
GET, variables:
Array
(
[This_is_a_GET_variable] => This is the GET value
)
POST, variables:
Array
(
[This_is_a_POST_variable] => This is the POST value
)
POST, raw:
This+is+a+POST+variable=This+is+the+POST+value
POST, raw:
This data is 100% raw! I can write whatever I want! ()YDF)/Y"PORKF_PSJUVYO U"V-ñOUMC-ñO()U;"=)#XI:
Searching webpage for a specific word
Code:
#include <amxmodx>#include <httpx>new Buffer[1024];
public plugin_init(){register_plugin("HTTP:X Searching chunks example", "1.0", "[ --{-@ ]");
HTTPX_Download("http://www.amxmodx.org", _, _, "Progress");
}public Progress(Index){new len, len2;
server_print("Downloaded data: %d/%d (+%d)", HTTPX_GetBytesReceived(Index), HTTPX_GetFilesize(Index), HTTPX_GetNewBytesReceived());
while(( len = HTTPX_GetData(Buffer, charsmax(Buffer)))){server_print("Reading data %d/%d", len, HTTPX_GetNewBytesReceived() - len2);
len2 += len;
if(contain(Buffer, "Context") != -1){server_print("Gaben was found");
return PLUGIN_HANDLED // This will stop the download.}}return PLUGIN_CONTINUE
}
Code:
Downloaded data: 2446/-1 (+2446)
Reading data 1023/2446
Reading data 1023/1423
Reading data 400/400
Downloaded data: 6443/-1 (+3997)
Reading data 1023/3997
Reading data 1023/2974
Reading data 1023/1951
Reading data 928/928
Gaben was found
Simple autoupdater
This will just download a file every X seconds and replace the old, new version or not.
This version will first download a text file containing a version number and compare that to the version of the plugin you have before actually updating. Saves traffic and eventual problems.
Code:
#include <amxmodx>enum{
REQUEST_GET,
REQUEST_POST
}
native HTTPX_Download(const URL[], const Filename[] = "", const CompleteHandler[] = "", const ProgressHandler[] = "", Port = 0, RequestType = REQUEST_GET, const Username[] = "", const Password[] = "", ... /* For possible future use */)
native HTTPX_GetData(data[], len)#define AUTOUPDATE_FILE_ID "76775"#define AUTOUPDATE_HOW_OFTEN 0 // Only use this when checking if a new version exists.newconst VersionNum = 100;
newconst VersionString[] = "1.00";
public plugin_init(){register_plugin("HTTP:X Autoupdate example 2", VersionString, "[ --{-@ ]");
HTTPX_Download("http://your.website.com/your_plugin/version.txt", "", "Complete", "", 80, REQUEST_GET, "", "", 0, -1);
}public Complete(DownloadID, Error){if( Error )return;
new temp[16];
HTTPX_GetData(temp, charsmax(temp));
if(str_to_num(temp) > VersionNum )
UpdatePlugin();
}
UpdatePlugin(){new hHTTPX = is_plugin_loaded("HTTP:X");
if( hHTTPX ){new filename[64];
get_plugin(hHTTPX, filename, charsmax(filename));
if(callfunc_begin("AutoupdatePlugin", filename) == 1){callfunc_push_int(get_plugin(-1));
callfunc_push_str(AUTOUPDATE_FILE_ID, false);
callfunc_push_int(AUTOUPDATE_HOW_OFTEN);
callfunc_end();
}}}
Even more advanced autoupdater (recommended)
This version will first check if HTTP:X exists before trying to use it's natives meaning your plugin will work as normal, just not automatically update if there's no HTTP:X.
It's the same method I use in all of my Ultimate Chat plugins.
enum{
REQUEST_GET,
REQUEST_POST
}/**
* HTTPX_IsFilesizeLarge(DownloadID)
*
* If the filesize in bytes is beyond the limitations of integers the function will return true.
**/
native bool:HTTPX_IsFilesizeLarge(DownloadID)/**
* HTTPX_GetBytesReceived(DownloadID)
*
* Returns total ammount of bytes received for DownloadID.
**/
native HTTPX_GetBytesReceived(DownloadID)/**
* HTTPX_GetBytesReceivedLarge(DownloadID, string[], len)
*
* Formats total ammount of bytes received for DownloadID in string form.
**/
native HTTPX_GetBytesReceivedLarge(DownloadID, string[], len)/**
* HTTPX_GetNewBytesReceived()
*
* Returns the ammount of bytes that was received in this chunk.
**/
native HTTPX_GetNewBytesReceived()/**
* HTTPX_GetFilesize(DownloadID)
*
* Returns the filesize of DownloadID.
* If unknown it will return -1.
**/
native HTTPX_GetFilesize(DownloadID)/**
* HTTPX_GetFilesizeLarge(DownloadID, string[], len)
*
* Formats the large filesize of DownloadID in string form.
**/
native HTTPX_GetFilesizeLarge(DownloadID, string[], len)/**
* HTTPX_GetFilename(DownloadID)
*
* Returns the filename of DownloadID.
**/
native HTTPX_GetFilename(DownloadID, name[], len)/**
* HTTPX_SetCustom(DownloadID, val)
*
* Set a custom value to follow along the download, retrievable as long as the download is in progress or on the complete call.
* If you want to pass more data than an int you could supply a dynamic array index instead.
*
* Returns 1 on success, 0 on fail.
**/
native HTTPX_SetCustom(DownloadID, any:val)/**
* HTTPX_GetCustom(DownloadID)
*
* Returns the previously set value.
* If the DownloadID is not found it will return -666.
**/
native any:HTTPX_GetCustom(DownloadID)/**
* HTTPX_GetData(data[], len)
*
* Fills variable data[] with the last chunk downloaded.
*
* len decides maxlen for the data[] variable.
* Remember, this is raw data.
* No need to make room for null at the end unless you're passing it to any function that is
* trying to automatically find the end by searching for null (any string function).
*
* The function will return the ammount of bytes that was written to the data[] variable.
*
* By looping this function until it returns 0, you can get all the data.
**/
native HTTPX_GetData(data[], len)/**
* Automatic updating
* Updates current plugin automatically (from AlliedModders webpage only, to prevent spreading of malicious code).
*
*
* The file ID has to be the same as it is on the forum webpage. (Check the link of the .amxx file ("Get Plugin" link))
*
*
* If frequency is supplied you can set how often to update the file. If none is provided it will update as soon as possible.
* Please use this respectfully. Don't overload the AM forums.
*
* You can however provide your own method of determining whether the file needs to be updated or not before calling this function.
* That way you don't stress AM servers when not required. An example of this is in the HTTPX source which uses this method.
*
* Examples:
* 1w = 604800
* 30d = 2592000
*
* I recommend using 30 days or more. How often do you update your code? (Honestly)
* If the time is set too short and/or is abused, I will remove the function completely.
*
*
* IMPORTANT!
* The reason for this not being a native is that it does not halt the plugin if HTTPX is not running. HTTPX and automatic updating is optional.
* Use this example. the File ID is the attachment in your post on the AM forums. Only use the ID, not the whole URL.
* For example:
* The plugin Name Replacer by anakin_cstrike, @http://forums.alliedmods.net/showthread.php?t=77401
* Scroll down and hover the "Get Plugin", there you see the file ID. Just replace the placeholder with that value.
* #define AUTOUPDATE_FILE_ID "76775"
* Add the time or create your own method of deciding when it's supposed to be updated and you're done.
#define AUTOUPDATE_FILE_ID "REPLACE_THIS_WITH_YOUR_FILE_ID"
#define AUTOUPDATE_HOW_OFTEN REPLACE_THIS_WITH_DESIRED_FREQUENCY // 1d = 86400, 1w = 604800, 30d = 2592000 (30d is recommended)
UpdatePlugin() {
new hHTTPX = is_plugin_loaded("HTTP:X");
if ( hHTTPX ) {
new filename[16];
get_plugin(hHTTPX, filename, charsmax(filename));
if ( callfunc_begin("AutoupdatePlugin", filename) == 1 ) {
callfunc_push_int(get_plugin(-1));
callfunc_push_str(AUTOUPDATE_FILE_ID, false);
callfunc_push_int(AUTOUPDATE_HOW_OFTEN);
callfunc_end();
}
}
}
**//**
* HTTPX_Abort(DownloadID, bool:DeleteFile = true)
*
* Aborts the transfer of selected download DownloadID.
* If DeleteFile is set to true the partially downloaded file will be deleted.
**/
native HTTPX_Abort(DownloadID, bool:DeleteFile = true)/**
* HTTPX_AddPostVar(const variable[], const value[])
*
* Adds a POST variable to the request.
* This function is used before HTTPX_Download() or HTTP_AddToQue(), similar to set/show hudmessage.
* It can be used multiple times before each download.
**/
native HTTPX_AddPostVar(const variable[], const value[])/**
* HTTPX_AddPostRaw(const data[])
*
* Adds raw POST data to the request.
* This function is used before HTTPX_Download() or HTTP_AddToQue(), similar to set/show hudmessage.
* It can be used multiple times before each download.
**/
native HTTPX_AddPostRaw(const data[])/**
* Number of parameters for the callbacks are 1 (DownloadID) for the progress event and 2 (DownloadID, Error) for the complete event.
* Error codes:
* 0 Download done. No problems encountered.
* Positive returns is unhandled HTTP return codes. For example 404.
* Negative is internal errors.
* -1 No response code was found in the HTTP response header or it was outside the accepted range (200-307).
* -2 Server is sending bad data or sizes for a chunked transfer or HTTPX has problems reading them.
* -3 Nothing received in last packet. Most likely due to an error.
* -4 HTTPX was redirected but could not follow due to a socket error.
* -5 HTTPX was redirected too many times. Usually happens when server is insisting on a SSL/TLS connection which HTTPX does not support.
**//**
* HTTPX_Download(const URL[], const Filename[] = "", const CompleteHandler[] = "", const ProgressHandler[] = "", Port = (80<<443), RequestType = REQUEST_GET, const Username[] = "", const Password[] = "", ...)
*
* Begins download of a URL. Read parameters for information.
*
*
* Parameters:
*
* const URL[]
* URL that you want to download.
*
* (Optional) const Filename[]
* Where should the information be stored? If no filename is entered it will download as a "stream".
* This means the data will be thrown away after it passes the buffer.
* You can read the data on progress forward and make use of it there.
*
* (Optional) const CompleteHandler[] = ""
* The function you want called when the download is complete.
*
* (Optional) const ProgressHandler[] = ""
* The function you want called when the download is in progress.
* This will be called every time data is downloaded.
*
* (Optional) Port = 0
* The port that should be used.
* If this is left at default it will use 80 for http and 443 for https (when supported).
*
* (Optional) RequestType = REQUEST_GET
* What type of request should be used.
* If this is left at default it will use GET.
* Possible values so far are REQUEST_GET and REQUEST_POST.
*
* (Optional) const Username[] = ""
* (Optional) const Password[] = ""
* These are used to login to sites that require you to.
* It's only used for Basic authentication, not POST for example.
*
* Returns an DownloadID of the download that may be used to abort the download.
**/
native HTTPX_Download(const URL[], const Filename[] = "", const CompleteHandler[] = "", const ProgressHandler[] = "", Port = 0, RequestType = REQUEST_GET, const Username[] = "", const Password[] = "", ... /* For possible future use */)
Changelog
Code:
Version 1.00
* Release.
Version 1.01
* Bugfix.
Version 1.10
* Added functions to set and get a custom value in integer form.
Version 1.11
* Moving webserver, updating DNS.
Additional notes:
I'm always open to suggestions, feedback and criticism. Please share your thoughts.
Didn't really look through your code thoroughly, but I noticed something. Why do you use callfunc_* natives in your auto-updater? Fake natives were made to avoid that, I believe, and it would make it simpler and easier to remember.
Also, here's something interesting you might want to take a look at: https://github.com/rsKliPPy/webserver_amxx. You could look at it as a server for the client you just wrote here, so it would allow cross-server communication with HTTP, almost like JS/AJAX. I was just too lazy past couple of months to add some finishing touches and release it. :/ Tell me what do you think about it.
I use callfunc_* because it doesn't make a plugin fail if the function doesn't exist.
That way, people can build autoupdate into their plugins but not make HTTP:X a requirement for it to run, just an option.
Honestly, I don't understand what the webserver is for.
Communication plugins are already out there with less overhead and more flexibility. This was not made to compete with them.
There is set_module_filter() if the API user decides he wants it optional when using natives.
Even if you want it to stay that way, you should wrap it into a stock functions in your include file. Along the lines of:
and callfunc might be also bad for a reason that it relies on plugin name, that is "httpx.amxx". That's pretty hardcoded in my opinion.
I know this may be going a bit offtopic, but the webserver is basically a module for hosting a HTTP server on top of a HL server. It's a GoldSrc/HL counterpart of Asherkin's HTTP server. It lets one program dynamic web pages with Pawn, just like you would do with PHP for example. Just a fun project and I brought that up as your plugin revolves around HTTP.
Cross-server communication was just an example what those two could do if they got their powers combined.
If a plugin was using the include there would be no point of autoupdating since it wouldn't pass the compiler. This is done intentionally.
I don't see how set_module_filter() would help in this case. I have never used that function and I'm having a hard time understanding what it actually does. If you can show me what your thoughts were I would appreciate it.
The hardcoded part I could edit easily. I'll do that tomorrow. Done
Thank you for your feedback.
I'm not very experienced in C(#/++). But as far as I can tell your HTTP server looks professional.
If a plugin was using the include there would be no point of autoupdating since it wouldn't pass the compiler. This is done intentionally.
I don't see how set_module_filter() would help in this case. I have never used that function and I'm having a hard time understanding what it actually does. If you can show me what your thoughts were I would appreciate it.
Oh, I totally misunderstood how the plugin updater works. I just saw that it actually downloads files from the web compiler, that wasn't obvious at first. Now I see why you used callfunc instead of creating a native, that explains it.
But here's the question then - what if a plugin includes a non-standard include file? Just like your own? That could be solved by copying include file's contents onto the top of the code, but that's not really the solution.
Quote:
Originally Posted by Black Rose
Thank you for your feedback.
Anytime. I really like this plugin/API and I am happy to help at improving it.
It depends on the include. Some things are just stupid to move into an include. ColorChat is a great example. One small, simple function that comes in too many different versions.
If people copied the code instead they would compile fine online and it wouldn't be so hard to find the right version of colorchat.
It got me thinking and I'm gonna create an add-on that will update plugins instead. I think that will be easier for everyone. But that still won't work with custom includes.
This can be solved by using another compiler with the proper includes but I will not use anything else than downloads from AM. Mainly because malicious code is rare and will be removed but also for the sake of the GPL being enforced here.