annotate src/c/openid.c @ 3:f59083771ee2

Saving associations
author Adam Chlipala <adam@chlipala.net>
date Sun, 26 Dec 2010 15:11:23 -0500
parents b757dc2bd2f6
children 2d409aff8800
rev   line source
adam@1 1 #include <string.h>
adam@1 2
adam@0 3 #include <openssl/sha.h>
adam@0 4 #include <curl/curl.h>
adam@1 5 #include <expat.h>
adam@0 6
adam@1 7 #include <openid.h>
adam@0 8
adam@3 9 #define BUF_MAX 10240
adam@3 10 #define BUF_INIT 1024
adam@3 11
adam@2 12 struct uw_OpenidFfi_discovery {
adam@2 13 uw_Basis_string endpoint, localId;
adam@2 14 };
adam@2 15
adam@2 16 uw_Basis_string uw_OpenidFfi_endpoint(uw_context ctx, uw_OpenidFfi_discovery d) {
adam@2 17 return d->endpoint;
adam@2 18 }
adam@2 19
adam@2 20 uw_Basis_string uw_OpenidFfi_localId(uw_context ctx, uw_OpenidFfi_discovery d) {
adam@2 21 return d->localId;
adam@2 22 }
adam@2 23
adam@0 24 uw_unit uw_OpenidFfi_init(uw_context ctx) {
adam@0 25 curl_global_init(CURL_GLOBAL_ALL);
adam@0 26
adam@0 27 return uw_unit_v;
adam@0 28 }
adam@1 29
adam@1 30 static CURL *curl(uw_context ctx) {
adam@1 31 CURL *r;
adam@1 32
adam@1 33 if (!(r = uw_get_global(ctx, "curl"))) {
adam@1 34 r = curl_easy_init();
adam@1 35 if (r)
adam@1 36 uw_set_global(ctx, "curl", r, curl_easy_cleanup);
adam@1 37 }
adam@1 38
adam@1 39 return r;
adam@1 40 }
adam@1 41
adam@1 42 typedef struct {
adam@1 43 uw_context ctx;
adam@2 44 uw_OpenidFfi_discovery d;
adam@1 45 } endpoint;
adam@1 46
adam@1 47 static void XMLCALL startElement(void *userData, const XML_Char *name, const XML_Char **atts) {
adam@1 48 endpoint *ep = userData;
adam@1 49
adam@1 50 if (!strcmp(name, "link")) {
adam@1 51 const XML_Char **attp;
adam@1 52 int found = 0;
adam@1 53
adam@1 54 for (attp = atts; *attp; attp += 2) {
adam@1 55 if (!strcmp(attp[0], "rel") && !strcmp(attp[1], "openid2.provider")) {
adam@1 56 found = 1;
adam@1 57 break;
adam@1 58 }
adam@1 59 }
adam@1 60
adam@1 61 if (found) {
adam@1 62 for (attp = atts; *attp; attp += 2) {
adam@1 63 if (!strcmp(attp[0], "href")) {
adam@2 64 ep->d->endpoint = uw_strdup(ep->ctx, attp[1]);
adam@1 65 return;
adam@1 66 }
adam@1 67 }
adam@1 68 }
adam@1 69 }
adam@1 70 }
adam@1 71
adam@1 72 static void XMLCALL endElement(void *userData, const XML_Char *name) {
adam@1 73 }
adam@1 74
adam@1 75 typedef struct {
adam@1 76 XML_Parser parser;
adam@1 77 int any_errors;
adam@3 78 } curl_discovery_data;
adam@1 79
adam@3 80 static size_t write_discovery_data(void *buffer, size_t size, size_t nmemb, void *userp) {
adam@3 81 curl_discovery_data *d = userp;
adam@1 82
adam@1 83 if (!XML_Parse(d->parser, buffer, size * nmemb, 0))
adam@1 84 d->any_errors = 1;
adam@1 85
adam@1 86 return size * nmemb;
adam@1 87 }
adam@1 88
adam@2 89 uw_OpenidFfi_discovery *uw_OpenidFfi_discover(uw_context ctx, uw_Basis_string id) {
adam@1 90 char *s;
adam@1 91 CURL *c = curl(ctx);
adam@3 92 curl_discovery_data cd = {};
adam@2 93 uw_OpenidFfi_discovery dy = uw_malloc(ctx, sizeof(struct uw_OpenidFfi_discovery));
adam@2 94 endpoint ep = {ctx, dy};
adam@1 95 CURLcode code;
adam@1 96
adam@2 97 dy->endpoint = dy->localId = NULL;
adam@2 98
adam@1 99 if (!strchr(id, ':')) {
adam@1 100 id = uw_Basis_strcat(ctx, "http://", id);
adam@1 101 if ((s = strchr(id, '#')) != NULL)
adam@1 102 *s = 0;
adam@1 103 } else if ((s = strchr(id, '#')) != NULL) {
adam@1 104 char *id2 = uw_malloc(ctx, s - id + 1);
adam@1 105 memcpy(id2, s, s - id);
adam@1 106 id2[s - id] = 0;
adam@1 107 id = id2;
adam@1 108 }
adam@1 109
adam@1 110 cd.parser = XML_ParserCreate(NULL);
adam@1 111 XML_SetUserData(cd.parser, &ep);
adam@1 112 uw_push_cleanup(ctx, (void (*)(void *))XML_ParserFree, cd.parser);
adam@1 113 XML_SetElementHandler(cd.parser, startElement, endElement);
adam@1 114
adam@1 115 curl_easy_setopt(c, CURLOPT_URL, id);
adam@3 116 curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, write_discovery_data);
adam@1 117 curl_easy_setopt(c, CURLOPT_WRITEDATA, &cd);
adam@1 118
adam@1 119 code = curl_easy_perform(c);
adam@1 120 uw_pop_cleanup(ctx);
adam@1 121
adam@2 122 if (code || !ep.d->endpoint)
adam@1 123 return NULL;
adam@2 124 else {
adam@2 125 uw_OpenidFfi_discovery *dyp = malloc(sizeof(uw_OpenidFfi_discovery));
adam@2 126 *dyp = ep.d;
adam@2 127 return dyp;
adam@2 128 }
adam@1 129 }
adam@3 130
adam@3 131 uw_OpenidFfi_inputs uw_OpenidFfi_createInputs(uw_context ctx) {
adam@3 132 uw_buffer *r = uw_malloc(ctx, sizeof(uw_buffer));
adam@3 133 uw_buffer_init(BUF_MAX, r, BUF_INIT);
adam@3 134 return r;
adam@3 135 }
adam@3 136
adam@3 137 static int okForPost(const char *s) {
adam@3 138 for (; *s; ++s)
adam@3 139 if (*s == '=' || *s == '&')
adam@3 140 return 0;
adam@3 141 return 1;
adam@3 142 }
adam@3 143
adam@3 144 uw_unit uw_OpenidFfi_addInput(uw_context ctx, uw_OpenidFfi_inputs buf, uw_Basis_string key, uw_Basis_string value) {
adam@3 145 if (!okForPost(key))
adam@3 146 uw_error(ctx, FATAL, "Invalid key for OpenID inputs");
adam@3 147 if (!okForPost(value))
adam@3 148 uw_error(ctx, FATAL, "Invalid value for OpenID inputs");
adam@3 149
adam@3 150 if (uw_buffer_used(buf) > 0)
adam@3 151 uw_buffer_append(buf, "&", 1);
adam@3 152
adam@3 153 uw_buffer_append(buf, key, strlen(key));
adam@3 154 uw_buffer_append(buf, "=", 1);
adam@3 155 uw_buffer_append(buf, value, strlen(value));
adam@3 156
adam@3 157 return uw_unit_v;
adam@3 158 }
adam@3 159
adam@3 160 uw_Basis_string uw_OpenidFfi_getOutput(uw_context ctx, uw_OpenidFfi_outputs buf, uw_Basis_string key) {
adam@3 161 char *s = buf->start;
adam@3 162
adam@3 163 for (; *s; s = strchr(strchr(s, 0)+1, 0)+1)
adam@3 164 if (!strcmp(key, s))
adam@3 165 return strchr(s, 0)+1;
adam@3 166
adam@3 167 return NULL;
adam@3 168 }
adam@3 169
adam@3 170 static size_t write_buffer_data(void *buffer, size_t size, size_t nmemb, void *userp) {
adam@3 171 uw_buffer *buf = userp;
adam@3 172
adam@3 173 uw_buffer_append(buf, buffer, size * nmemb);
adam@3 174
adam@3 175 return size * nmemb;
adam@3 176 }
adam@3 177
adam@3 178 const char curl_failure[] = "error\0Error fetching URL";
adam@3 179
adam@3 180 uw_OpenidFfi_outputs uw_OpenidFfi_indirect(uw_context ctx, uw_Basis_string url, uw_OpenidFfi_inputs inps) {
adam@3 181 uw_buffer *buf = uw_malloc(ctx, sizeof(uw_buffer));
adam@3 182 CURL *c = curl(ctx);
adam@3 183 CURLcode code;
adam@3 184
adam@3 185 uw_buffer_init(BUF_MAX, buf, BUF_INIT);
adam@3 186
adam@3 187 uw_buffer_append(inps, "", 1);
adam@3 188
adam@3 189 curl_easy_setopt(c, CURLOPT_URL, url);
adam@3 190 curl_easy_setopt(c, CURLOPT_POSTFIELDS, inps->start);
adam@3 191 curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, write_buffer_data);
adam@3 192 curl_easy_setopt(c, CURLOPT_WRITEDATA, buf);
adam@3 193
adam@3 194 code = curl_easy_perform(c);
adam@3 195
adam@3 196 uw_buffer_append(buf, "", 1);
adam@3 197
adam@3 198 if (code) {
adam@3 199 uw_buffer_reset(buf);
adam@3 200 uw_buffer_append(buf, curl_failure, sizeof curl_failure);
adam@3 201 } else {
adam@3 202 char *s;
adam@3 203
adam@3 204 s = buf->start;
adam@3 205 while (*s) {
adam@3 206 char *colon = strchr(s, ':'), *newline;
adam@3 207
adam@3 208 if (!colon) {
adam@3 209 *s = 0;
adam@3 210 break;
adam@3 211 }
adam@3 212
adam@3 213 newline = strchr(colon+1, '\n');
adam@3 214
adam@3 215 if (!newline) {
adam@3 216 *s = 0;
adam@3 217 break;
adam@3 218 }
adam@3 219
adam@3 220 *colon = 0;
adam@3 221 *newline = 0;
adam@3 222 s = newline+1;
adam@3 223 }
adam@3 224 }
adam@3 225
adam@3 226 return buf;
adam@3 227 }