perlなら20数行だし、pythonで書いても大した事にはならないだろう...。
Basic認証ならまだしも、WSSEなんか使ったら敷居も高いし、派生アプリケーションが出てこなくなるのはもう分かってるはず。
C++で書くと、こんな事になるんだ...
#以下ソース
#例によって適当クオリティなので添削し放題です。
#include <iostream>
#include <string>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <curl/curl.h>
#ifndef uint8
#define uint8 unsigned char
#endif
#ifndef uint32
#define uint32 unsigned long int
#endif
#ifndef uint64
# ifdef _WIN32
# ifdef __GNUC__
# define uint64 unsigned __int64
# else
# define uint64 unsigned _int64
# endif
# else
# define uint64 unsigned long long
# endif
#endif
#ifndef byte
# define byte unsigned char
#endif
typedef struct
{
uint32 total[2];
uint32 state[5];
uint8 buffer[64];
} sha1_context;
#define GET_UINT32(n,b,i) \
{ \
(n) = ( (uint32) (b)[(i) ] << 24 ) \
| ( (uint32) (b)[(i) + 1] << 16 ) \
| ( (uint32) (b)[(i) + 2] << 8 ) \
| ( (uint32) (b)[(i) + 3] ); \
}
#define PUT_UINT32(n,b,i) \
{ \
(b)[(i) ] = (uint8) ( (n) >> 24 ); \
(b)[(i) + 1] = (uint8) ( (n) >> 16 ); \
(b)[(i) + 2] = (uint8) ( (n) >> 8 ); \
(b)[(i) + 3] = (uint8) ( (n) ); \
}
static void sha1_starts(
sha1_context *ctx)
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
}
static void sha1_process(
sha1_context *ctx, uint8 data[64])
{
uint32 temp, W[16], A, B, C, D, E;
GET_UINT32( W[0], data, 0 );
GET_UINT32( W[1], data, 4 );
GET_UINT32( W[2], data, 8 );
GET_UINT32( W[3], data, 12 );
GET_UINT32( W[4], data, 16 );
GET_UINT32( W[5], data, 20 );
GET_UINT32( W[6], data, 24 );
GET_UINT32( W[7], data, 28 );
GET_UINT32( W[8], data, 32 );
GET_UINT32( W[9], data, 36 );
GET_UINT32( W[10], data, 40 );
GET_UINT32( W[11], data, 44 );
GET_UINT32( W[12], data, 48 );
GET_UINT32( W[13], data, 52 );
GET_UINT32( W[14], data, 56 );
GET_UINT32( W[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define R(t) \
( \
temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \
W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \
( W[t & 0x0F] = S(temp,1) ) \
)
#define P(a,b,c,d,e,x) \
{ \
e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
#define F(x,y,z) (z ^ (x & (y ^ z)))
#define K 0x5A827999
P( A, B, C, D, E, W[0] );
P( E, A, B, C, D, W[1] );
P( D, E, A, B, C, W[2] );
P( C, D, E, A, B, W[3] );
P( B, C, D, E, A, W[4] );
P( A, B, C, D, E, W[5] );
P( E, A, B, C, D, W[6] );
P( D, E, A, B, C, W[7] );
P( C, D, E, A, B, W[8] );
P( B, C, D, E, A, W[9] );
P( A, B, C, D, E, W[10] );
P( E, A, B, C, D, W[11] );
P( D, E, A, B, C, W[12] );
P( C, D, E, A, B, W[13] );
P( B, C, D, E, A, W[14] );
P( A, B, C, D, E, W[15] );
P( E, A, B, C, D, R(16) );
P( D, E, A, B, C, R(17) );
P( C, D, E, A, B, R(18) );
P( B, C, D, E, A, R(19) );
#undef K
#undef F
#define F(x,y,z) (x ^ y ^ z)
#define K 0x6ED9EBA1
P( A, B, C, D, E, R(20) );
P( E, A, B, C, D, R(21) );
P( D, E, A, B, C, R(22) );
P( C, D, E, A, B, R(23) );
P( B, C, D, E, A, R(24) );
P( A, B, C, D, E, R(25) );
P( E, A, B, C, D, R(26) );
P( D, E, A, B, C, R(27) );
P( C, D, E, A, B, R(28) );
P( B, C, D, E, A, R(29) );
P( A, B, C, D, E, R(30) );
P( E, A, B, C, D, R(31) );
P( D, E, A, B, C, R(32) );
P( C, D, E, A, B, R(33) );
P( B, C, D, E, A, R(34) );
P( A, B, C, D, E, R(35) );
P( E, A, B, C, D, R(36) );
P( D, E, A, B, C, R(37) );
P( C, D, E, A, B, R(38) );
P( B, C, D, E, A, R(39) );
#undef K
#undef F
#define F(x,y,z) ((x & y) | (z & (x | y)))
#define K 0x8F1BBCDC
P( A, B, C, D, E, R(40) );
P( E, A, B, C, D, R(41) );
P( D, E, A, B, C, R(42) );
P( C, D, E, A, B, R(43) );
P( B, C, D, E, A, R(44) );
P( A, B, C, D, E, R(45) );
P( E, A, B, C, D, R(46) );
P( D, E, A, B, C, R(47) );
P( C, D, E, A, B, R(48) );
P( B, C, D, E, A, R(49) );
P( A, B, C, D, E, R(50) );
P( E, A, B, C, D, R(51) );
P( D, E, A, B, C, R(52) );
P( C, D, E, A, B, R(53) );
P( B, C, D, E, A, R(54) );
P( A, B, C, D, E, R(55) );
P( E, A, B, C, D, R(56) );
P( D, E, A, B, C, R(57) );
P( C, D, E, A, B, R(58) );
P( B, C, D, E, A, R(59) );
#undef K
#undef F
#define F(x,y,z) (x ^ y ^ z)
#define K 0xCA62C1D6
P( A, B, C, D, E, R(60) );
P( E, A, B, C, D, R(61) );
P( D, E, A, B, C, R(62) );
P( C, D, E, A, B, R(63) );
P( B, C, D, E, A, R(64) );
P( A, B, C, D, E, R(65) );
P( E, A, B, C, D, R(66) );
P( D, E, A, B, C, R(67) );
P( C, D, E, A, B, R(68) );
P( B, C, D, E, A, R(69) );
P( A, B, C, D, E, R(70) );
P( E, A, B, C, D, R(71) );
P( D, E, A, B, C, R(72) );
P( C, D, E, A, B, R(73) );
P( B, C, D, E, A, R(74) );
P( A, B, C, D, E, R(75) );
P( E, A, B, C, D, R(76) );
P( D, E, A, B, C, R(77) );
P( C, D, E, A, B, R(78) );
P( B, C, D, E, A, R(79) );
#undef K
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
}
static void sha1_update(
sha1_context *ctx,
uint8 *input,
uint32 length)
{
uint32 left, fill;
if (!length)
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += length;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < length)
ctx->total[1]++;
if (left && length >= fill) {
memcpy((void*)(ctx->buffer + left), (void*)input, fill);
sha1_process(ctx, ctx->buffer);
length -= fill;
input += fill;
left = 0;
}
while (length >= 64) {
sha1_process(ctx, input);
length -= 64;
input += 64;
}
if (length)
memcpy((void*)(ctx->buffer + left), (void *)input, length );
}
static uint8 sha1_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static void sha1_finish(
sha1_context *ctx,
uint8 digest[20])
{
uint32 last, padn;
uint32 high, low;
uint8 msglen[8];
high = (ctx->total[0] >> 29)
| (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
PUT_UINT32(high, msglen, 0);
PUT_UINT32(low, msglen, 4);
last = ctx->total[0] & 0x3F;
padn = (last < 56) ? (56 - last) : (120 - last);
sha1_update(ctx, sha1_padding, padn);
sha1_update(ctx, msglen, 8);
PUT_UINT32(ctx->state[0], digest, 0);
PUT_UINT32(ctx->state[1], digest, 4);
PUT_UINT32(ctx->state[2], digest, 8);
PUT_UINT32(ctx->state[3], digest, 12);
PUT_UINT32(ctx->state[4], digest, 16);
}
static std::string sha1(
const std::string& input)
{
std::string digest;
sha1_context ctx;
sha1_starts(&ctx);
sha1_update(&ctx, (uint8*)&input[0], input.size());
digest.resize(20);
sha1_finish(&ctx, (uint8*)&digest[0]);
return digest;
}
static const char hex_table[] = "0123456789abcdef";
static std::string string_to_hex(
const std::string& input)
{
std::string temp;
temp.resize(input.size() * 2);
std::string::size_type i;
std::string::const_iterator itr = input.begin();
for (i = 0; itr != input.end(); itr++, i++)
{
temp[i++] = hex_table[(*itr & 0xF0) >> 4];
temp[i] = hex_table[*itr & 0x0F];
}
return temp;
}
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
#define is_base64(c) ( \
isalnum((unsigned char)c) || \
((unsigned char)c == '+') || \
((unsigned char)c == '/'))
static std::string base64_encode(
unsigned char const* bytes_to_encode,
unsigned int in_len)
{
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3] = {0};
unsigned char char_array_4[4] = {0};
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; i <4; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i) {
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
static std::string get_nonce()
{
static bool initialized = false;
if (!initialized)
srand((unsigned int)time(NULL));
char buf[256];
sprintf(buf, "%d %d", time(NULL), rand());
return string_to_hex(sha1(buf));
}
static std::string get_time()
{
time_t timer;
struct tm *date;
timer = time(NULL);
date = localtime(&timer);
char buf[256];
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", date);
return buf;
}
static std::string responseBuf;
static int handle_returned_data(
char* ptr,
size_t size,
size_t nmemb,
void* stream)
{
char* pbuf = new char[size*nmemb+1];
memcpy(pbuf, ptr, size*nmemb);
pbuf[size*nmemb] = 0;
responseBuf += pbuf;
delete[] pbuf;
return size*nmemb;
}
static int register_namespaces(
xmlXPathContextPtr xpathCtx,
const xmlChar* nsList)
{
xmlChar* nsListDup;
xmlChar* prefix;
xmlChar* href;
xmlChar* next;
nsListDup = xmlStrdup(nsList);
if (nsListDup == NULL) return -1;
next = nsListDup;
while(next != NULL) {
while(isspace(*next)) next++;
if((*next) == '\0') break;
prefix = next;
next = (xmlChar*)xmlStrchr(next, '=');
if (!next) {
xmlFree(nsListDup);
return -1;
}
*(next++) = '\0';
href = next;
next = (xmlChar*)xmlStrchr(next, ' ');
if (next) {
*(next++) = '\0';
}
if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0) {
xmlFree(nsListDup);
return -1;
}
}
xmlFree(nsListDup);
return(0);
}
static std::string query_xml(
std::string& xml,
std::string query,
std::string ns = "")
{
xmlDocPtr pDoc = xmlParseDoc((xmlChar*)xml.c_str());
xmlAttrPtr pAttr = NULL;
xmlXPathContextPtr xpathCtx = NULL;
xmlXPathObjectPtr xpathObj=NULL;
xmlNodeSetPtr nodes;
std::string ret;
int n;
if (!pDoc) goto leave;
xpathCtx = xmlXPathNewContext(pDoc);
if (!xpathCtx) goto leave;
if (ns.size()) {
if (register_namespaces(xpathCtx, (xmlChar*)ns.c_str()) < 0)
goto leave;
}
xpathObj = xmlXPathEvalExpression((xmlChar*)query.c_str(), xpathCtx);
if (!xpathObj) goto leave;
nodes = xpathObj->nodesetval;
for(n = 0; n < xmlXPathNodeSetGetLength(nodes); n++) {
xmlNodePtr node = nodes->nodeTab[n];
if(node->type != XML_ATTRIBUTE_NODE && node->type != XML_ELEMENT_NODE && node->type != XML_CDATA_SECTION_NODE) continue;
if (node->type == XML_CDATA_SECTION_NODE)
ret = (char*)node->content;
else
if (node->children)
ret = (char*)node->children->content;
break;
}
leave:
if (xpathObj) xmlXPathFreeObject(xpathObj);
if (xpathCtx) xmlXPathFreeContext(xpathCtx);
if (pDoc) xmlFreeDoc(pDoc);
return ret;
}
static std::string get_content(
std::string url,
std::string username,
std::string password)
{
std::string ret;
std::string nonce = get_nonce();
std::string post_time = get_time();
std::string header;
std::string base64nonce = base64_encode(
(unsigned char const*)nonce.c_str(), nonce.size());
std::string pass = nonce;
pass += post_time;
pass += password;
pass = sha1(pass);
std::string base64pass = base64_encode(
(unsigned char const*)pass.c_str(), pass.size());
std::string authorization_header;
authorization_header += "UsernameToken ";
authorization_header += "Username=\"";
authorization_header += username + "\", ";
authorization_header += "PasswordDigest=\"";
authorization_header += base64pass + "\", ";
authorization_header += "Created=\"";
authorization_header += post_time + "\", ";
authorization_header += "Nonce=\"";
authorization_header += base64nonce + "\"";
CURL* curl;
CURLcode res;
struct curl_slist *headerlist = NULL;
long status = 0;
curl = curl_easy_init();
if (!curl) goto leave;
header = "Content-Type: application/x.atom+xml";
headerlist = curl_slist_append(headerlist, header.c_str());
header = "X-WSSE: ";
header += authorization_header.c_str();
headerlist = curl_slist_append(headerlist, header.c_str());
header = "Authorization: WSSE profile=\"UsernameToken\"";
headerlist = curl_slist_append(headerlist, header.c_str());
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
responseBuf = "";
res = curl_easy_perform(curl);
#ifdef _DEBUG
{
FILE *fp = fopen("res.xml", "wb");
fprintf(fp, "%s", responseBuf.c_str());
fclose(fp);
}
#endif
if (res != CURLE_OK) goto leave;
res = curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &status);
if (res != CURLE_OK || status != 200) goto leave;
ret = responseBuf;
leave:
responseBuf = "";
curl_easy_cleanup(curl);
return ret;
}
#ifdef _WIN32
static std::string utf8_to_string(std::string str)
{
std::string strRet;
UINT codePage = CP_UTF8;
const char* ptr = str.c_str();
if (str[0] == (char)0xef && str[1] == (char)0xbb && str[2] == (char)0xbf)
ptr += 3;
size_t wcssize = MultiByteToWideChar(codePage, 0, ptr, -1, NULL, 0);
wchar_t* pszStr = new wchar_t[wcssize + 1];
wcssize = MultiByteToWideChar(codePage, 0, ptr, -1, pszStr, wcssize + 1);
pszStr[wcssize] = '\0';
codePage = GetACP();
size_t mbssize = WideCharToMultiByte(codePage, 0, (LPCWSTR)pszStr,-1,NULL,0,NULL,NULL);
char* pszStrMB = new char[mbssize+1];
mbssize = WideCharToMultiByte(codePage, 0, (LPCWSTR)pszStr, -1, pszStrMB, mbssize, NULL, NULL);
pszStrMB[mbssize] = '\0';
strRet = pszStrMB;
delete [] pszStrMB;
delete [] pszStr;
return strRet;
}
#endif
static void dump_content(
std::string& xml)
{
xmlDocPtr pDoc = xmlParseDoc((xmlChar*)xml.c_str());
xmlAttrPtr pAttr = NULL;
xmlXPathContextPtr xpathCtx = NULL;
xmlXPathObjectPtr xpathObj=NULL;
xmlNodeSetPtr nodes;
std::string ret;
int n;
if (!pDoc) goto leave;
xpathCtx = xmlXPathNewContext(pDoc);
if (!xpathCtx) goto leave;
if (register_namespaces(xpathCtx, (xmlChar*)"Atom=http://www.w3.org/2005/Atom") < 0)
goto leave;
xpathObj = xmlXPathEvalExpression((xmlChar*)"/Atom:feed/Atom:entry", xpathCtx);
if (!xpathObj) goto leave;
nodes = xpathObj->nodesetval;
for(n = 0; n < xmlXPathNodeSetGetLength(nodes); n++) {
xmlNodePtr node = nodes->nodeTab[n]->children;
while(node) {
std::string name = (char*)node->name;
#ifdef _WIN32
if (name == "title")
std::cout << "name:" << utf8_to_string((char*)node->children->content) << std::endl;
#else
if (name == "title")
std::cout << "name:" << (char*)node->children->content << std::endl;
#endif
if (name == "updated")
std::cout << "time:" << (char*)node->children->content << std::endl;
if (name == "link")
std::cout << "link:" << (char*)xmlGetProp(node, (xmlChar*)"href") << std::endl;
node = node->next;
}
std::cout << std::endl;
}
leave:
if (xpathObj) xmlXPathFreeObject(xpathObj);
if (xpathCtx) xmlXPathFreeContext(xpathCtx);
if (pDoc) xmlFreeDoc(pDoc);
}
int main(int argc, char* argv[])
{
std::string username;
std::string password;
if (argc != 3) return -1;
username = argv[1];
password = argv[2];
std::string xml, value;
xml = get_content(
"http://mixi.jp/atom/tracks",
username,
password);
value = query_xml(
xml,
"/app:service/app:workspace/app:collection/@href",
"app=http://purl.org/atom/app#");
xml = get_content(
value,
username,
password);
dump_content(xml);
return 0;
}
これでSTLを使えなかったとしたら...ガクガク((((;゚Д゚))))ブルブル