private async Task <XmlDocument> GetCreatedEntity(HttpResponseMessage postResponse, PostNewImageResult result) { result.editUri = postResponse.Headers["Location"]; string contentLocation = postResponse.Headers["Content-Location"]; if (string.IsNullOrEmpty(result.editUri) || result.editUri != contentLocation) { XmlRestRequestHelper.XmlRequestResult xmlResult = new XmlRestRequestHelper.XmlRequestResult(); xmlResult.uri = postResponse.RequestMessage.RequestUri; if (!string.IsNullOrEmpty(result.editUri)) { xmlResult.uri = new Uri(result.editUri); } XmlDocument doc = await xmlRestRequestHelper.Get(_requestFilter, xmlResult); result.etag = xmlResult.responseHeaders["ETag"]; return(doc); } else { result.etag = postResponse.Headers["ETag"]; XmlDocument xmlDoc = new XmlDocument(); var xml = await postResponse.Content.ReadAsStringAsync(); xmlDoc.LoadXml(xml); XmlHelper.ApplyBaseUri(xmlDoc, postResponse.RequestMessage.RequestUri); return(xmlDoc); } }
public async Task <BlogPost> GetPost(string blogId, string postId) { Login(); FixupBlogId(ref blogId); XmlRestRequestHelper.XmlRequestResult result = new XmlRestRequestHelper.XmlRequestResult(); result.uri = PostIdToPostUri(postId); result.responseHeaders = new HttpResponseMessage().Headers; var doc = await xmlRestRequestHelper.Get(RequestFilter, result); XmlDocument remotePost = (XmlDocument)doc.CloneNode(true); XmlElement entryNode = doc.SelectSingleNodeNS("/atom:entry", _nsMgr.ToNSMethodFormat()) as XmlElement; if (entryNode == null) { throw new BlogClientInvalidServerResponseException("GetPost", "No post entry returned from server", doc.GetXml()); } BlogPost post = Parse(entryNode, true, result.uri); post.Id = postId; post.ETag = FilterWeakEtag(result.responseHeaders["ETag"]); post.AtomRemotePost = remotePost; return(post); }
protected virtual async Task <XmlDocument> GetCategoryXml(string blogId) { // Get the service document Login(); FixupBlogId(ref blogId); XmlRestRequestHelper.XmlRequestResult result = new XmlRestRequestHelper.XmlRequestResult(); result.uri = FeedServiceUrl; var xmlDoc = await xmlRestRequestHelper.Get(RequestFilter, result); foreach (XmlElement entryEl in xmlDoc.SelectNodesNS("app:service/app:workspace/app:collection", _nsMgr.ToNSMethodFormat())) { string href = XmlHelper.GetUrl(entryEl, "@href", result.uri); if (blogId == href) { XmlDocument results = new XmlDocument(); XmlElement rootElement = results.CreateElement("categoryInfo"); results.AppendChild(rootElement); foreach (XmlElement categoriesNode in entryEl.SelectNodesNS("app:categories", _nsMgr.ToNSMethodFormat())) { await AddCategoriesXml(categoriesNode, rootElement, result); } return(results); } } //Debug.Fail("Couldn't find collection in service document:\r\n" + xmlDoc.OuterXml); return(new XmlDocument()); }
protected virtual async Task UpdateImage(bool allowWriteStreamBuffering, string editMediaUri, string path, string editEntryUri, string etag, bool getEditInfo, PostNewImageResult result) { HttpResponseMessage response = null; try { response = await RedirectHelper.GetResponse(editMediaUri, new RedirectHelper.RequestFactory(new ImageUploadHelper(this, path, "PUT", etag, allowWriteStreamBuffering).Create)); } catch (WebException we) { bool recovered = false; if (we.Status == WebExceptionStatus.ProtocolError && we.Response != null) { HttpWebResponse errResponse = we.Response as HttpWebResponse; if (errResponse != null && errResponse.StatusCode == HttpStatusCode.PreconditionFailed) { string newEtag = await AtomClient.GetEtag(editMediaUri, _requestFilter); if (newEtag != null && newEtag.Length > 0 && newEtag != etag) { if (!AtomClient.ConfirmOverwrite()) { throw new BlogClientOperationCancelledException(); } try { response = await RedirectHelper.GetResponse(editMediaUri, new RedirectHelper.RequestFactory(new ImageUploadHelper(this, path, "PUT", newEtag, allowWriteStreamBuffering).Create)); } finally { if (response != null) { response.Dispose(); } } recovered = true; } } else if (!allowWriteStreamBuffering) { // The error may have been due to the server requiring stream buffering (WinLive 114314, 252175) // Try again with stream buffering. await UpdateImage(true, editMediaUri, path, editEntryUri, etag, getEditInfo, result); recovered = true; } } if (!recovered) { throw; } } // Check to see if we are going to get the src url and the etag, in most cases we will want to get this // information, but in the case of a photo album, since we never edit the image or link directly to them // we don't need the information and it can saves an http request. if (getEditInfo) { string selfPage; XmlRestRequestHelper.XmlRequestResult xmlResult = new XmlRestRequestHelper.XmlRequestResult(); xmlResult.uri = new Uri(editEntryUri); XmlDocument mediaLinkEntry = await xmlRestRequestHelper.Get(_requestFilter, xmlResult); ParseResponse(mediaLinkEntry, result); } else { //thumbnailSmall = null; //thumbnailLarge = null; //srcUrl = null; } }
public async Task <string> NewPost(string blogId, BlogPost post, INewCategoryContext newCategoryContext, bool publish, PostResult postResult) { if (!publish && !Options.SupportsPostAsDraft) { //Debug.Fail("Post to draft not supported on this provider"); throw new BlogClientPostAsDraftUnsupportedException(); } Login(); FixupBlogId(ref blogId); XmlDocument doc = new XmlDocument(); XmlElement entryNode = doc.CreateElementNS(_atomNS.Uri, _atomNS.Prefix + ":entry"); doc.AppendChild(entryNode); Populate(post, null, entryNode, publish); string slug = null; if (Options.SupportsSlug) { slug = post.Slug; } XmlRestRequestHelper.XmlRequestResult xmlResult2 = new XmlRestRequestHelper.XmlRequestResult(); xmlResult2.uri = new Uri(blogId); XmlDocument result = await xmlRestRequestHelper.Post( new HttpAsyncRequestFilter(new NewPostRequest(this, slug).RequestFilter), ENTRY_CONTENT_TYPE, doc, _clientOptions.CharacterSet, xmlResult2); postResult.ETag = FilterWeakEtag(xmlResult2.responseHeaders["ETag"]); string location = xmlResult2.responseHeaders["Location"]; if (string.IsNullOrEmpty(location)) { throw new BlogClientInvalidServerResponseException("POST", "The HTTP response was missing the required Location header.", ""); } if (location != xmlResult2.responseHeaders["Content-Location"] || result == null) { XmlRestRequestHelper.XmlRequestResult xmlResult = new XmlRestRequestHelper.XmlRequestResult(); xmlResult.uri = new Uri(location); result = await xmlRestRequestHelper.Get(RequestFilter, xmlResult); postResult.ETag = FilterWeakEtag(xmlResult.responseHeaders["ETag"]); } postResult.AtomRemotePost = (XmlDocument)result.CloneNode(true); Parse(result.DocumentElement, true, xmlResult2.uri); if (Options.SupportsNewCategories) { foreach (BlogPostCategory category in post.NewCategories) { newCategoryContext.NewCategoryAdded(category); } } return(PostUriToPostId(location)); }
protected async Task <BlogInfo[]> GetUsersBlogsInternal() { XmlRestRequestHelper.XmlRequestResult xmlResult = new XmlRestRequestHelper.XmlRequestResult(); xmlResult.uri = FeedServiceUrl; XmlDocument xmlDoc = await xmlRestRequestHelper.Get(RequestFilter, xmlResult); // Either the FeedServiceUrl points to a service document OR a feed. if (xmlDoc.SelectSingleNodeNS("/app:service", _nsMgr.ToNSMethodFormat()) != null) { ArrayList blogInfos = new ArrayList(); foreach (XmlElement coll in xmlDoc.SelectNodesNS("/app:service/app:workspace/app:collection", _nsMgr.ToNSMethodFormat())) { bool promote = ShouldPromote(coll); // does this collection accept entries? XmlNodeList acceptNodes = coll.SelectNodesNS("app:accept", _nsMgr.ToNSMethodFormat()); bool acceptsEntries = false; if (acceptNodes.Count == 0) { acceptsEntries = true; } else { foreach (XmlElement acceptNode in acceptNodes) { if (AcceptsEntry(acceptNode.InnerText)) { acceptsEntries = true; break; } } } if (acceptsEntries) { string feedUrl = XmlHelper.GetUrl(coll, "@href", xmlResult.uri); if (feedUrl == null || feedUrl.Length == 0) { continue; } // form title StringBuilder titleBuilder = new StringBuilder(); foreach (XmlElement titleContainerNode in new XmlElement[] { coll.ParentNode as XmlElement, coll }) { Debug.Assert(titleContainerNode != null); if (titleContainerNode != null) { XmlElement titleNode = titleContainerNode.SelectSingleNodeNS("atom:title", _nsMgr.ToNSMethodFormat()) as XmlElement; if (titleNode != null) { string titlePart = _atomVer.TextNodeToPlaintext(titleNode); if (titlePart.Length != 0) { //Res.LOCME("loc the separator between parts of the blog name"); if (titleBuilder.Length != 0) { titleBuilder.Append(" - "); } titleBuilder.Append(titlePart); } } } } // get homepage URL string homepageUrl = ""; string dummy = ""; XmlRestRequestHelper.XmlRequestResult xmlResult2 = new XmlRestRequestHelper.XmlRequestResult(); xmlResult2.uri = new Uri(feedUrl); XmlDocument feedDoc = await xmlRestRequestHelper.Get(RequestFilter, xmlResult2); ParseFeedDoc(feedDoc, xmlResult2.uri, false, ref homepageUrl, ref dummy); // TODO: Sniff out the homepage URL BlogInfo blogInfo = new BlogInfo(feedUrl, titleBuilder.ToString().Trim(), homepageUrl); if (promote) { blogInfos.Insert(0, blogInfo); } else { blogInfos.Add(blogInfo); } } } return((BlogInfo[])blogInfos.ToArray(typeof(BlogInfo))); } else { string title = string.Empty; string homepageUrl = string.Empty; ParseFeedDoc(xmlDoc, xmlResult.uri, true, ref homepageUrl, ref title); return(new BlogInfo[] { new BlogInfo(UrlHelper.SafeToAbsoluteUri(FeedServiceUrl), title, homepageUrl) }); } }
public virtual async Task <bool> EditPost(string blogId, BlogPost post, INewCategoryContext newCategoryContext, bool publish, EditPostResult result) { if (!publish && !Options.SupportsPostAsDraft) { //Debug.Fail("Post to draft not supported on this provider"); throw new BlogClientPostAsDraftUnsupportedException(); } Login(); FixupBlogId(ref blogId); XmlDocument doc = post.AtomRemotePost; XmlElement entryNode = doc.SelectSingleNodeNS("/atom:entry", _nsMgr.ToNSMethodFormat()) as XmlElement; // No documentUri is needed because we ensure xml:base is set on the root // when we retrieve from XmlRestRequestHelper Populate(post, null, entryNode, publish); string etagToMatch = FilterWeakEtag(post.ETag); try { retry: try { XmlRestRequestHelper.XmlRequestResult xmlResult2 = new XmlRestRequestHelper.XmlRequestResult(); xmlResult2.uri = PostIdToPostUri(post.Id); await xmlRestRequestHelper.Put(etagToMatch, RequestFilter, ENTRY_CONTENT_TYPE, doc, _clientOptions.CharacterSet, true, xmlResult2); } catch (WebException we) { if (we.Status == WebExceptionStatus.ProtocolError) { if (((HttpWebResponse)we.Response).StatusCode == HttpStatusCode.PreconditionFailed) { if (etagToMatch != null && etagToMatch.Length > 0) { HttpRequestHelper.LogException(we); string currentEtag = await GetEtag(UrlHelper.SafeToAbsoluteUri(PostIdToPostUri(post.Id))); if (currentEtag != null && currentEtag.Length > 0 && currentEtag != etagToMatch) { if (ConfirmOverwrite()) { etagToMatch = currentEtag; goto retry; } else { throw new BlogClientOperationCancelledException(); } } } } } throw; } } catch (Exception e) { if (!AttemptEditPostRecover(e, blogId, post, newCategoryContext, publish, result)) { // convert to a provider exception if this is a 404 (allow us to // catch this case explicitly and attempt a new post to recover) if (e is WebException) { WebException webEx = e as WebException; HttpWebResponse response = webEx.Response as HttpWebResponse; if (response != null && response.StatusCode == HttpStatusCode.NotFound) { throw new BlogClientProviderException("404", e.Message); } } // no special handling, just re-throw throw; } } XmlRestRequestHelper.XmlRequestResult xmlResult = new XmlRestRequestHelper.XmlRequestResult(); xmlResult.uri = PostIdToPostUri(post.Id); xmlResult.responseHeaders = new HttpResponseMessage().Headers; result.remotePost = await xmlRestRequestHelper.Get(RequestFilter, xmlResult); result.etag = FilterWeakEtag(xmlResult.responseHeaders["ETag"]); //Debug.Assert(remotePost != null, "After successful PUT, remote post could not be retrieved"); if (Options.SupportsNewCategories) { foreach (BlogPostCategory category in post.NewCategories) { newCategoryContext.NewCategoryAdded(category); } } return(true); }
protected async Task <BlogPost[]> GetRecentPostsInternal(string blogId, int maxPosts, bool includeCategories, DateTime?now) { Login(); FixupBlogId(ref blogId); HashSet <string> seenIds = new HashSet <string>(); ArrayList blogPosts = new ArrayList(); try { while (true) { XmlDocument doc; XmlRestRequestHelper.XmlRequestResult result = new XmlRestRequestHelper.XmlRequestResult(); result.uri = new Uri(blogId); // This while-loop nonsense is necessary because New Blogger has a bug // where the official URL for getting recent posts doesn't work when // the orderby=published flag is set, but there's an un-official URL // that will work correctly. Therefore, subclasses need the ability // to inspect exceptions that occur, along with the URI that was used // to make the request, and determine whether an alternate URI should // be used. while (true) { try { doc = await xmlRestRequestHelper.Get(RequestFilter, result); break; } catch (Exception e) { //Debug.WriteLine(e.ToString()); if (AttemptAlternateGetRecentPostUrl(e, ref blogId)) { continue; } else { throw; } } } XmlNodeList nodeList = doc.SelectNodesNS("/atom:feed/atom:entry", _nsMgr.ToNSMethodFormat()); if (nodeList.Count == 0) { break; } foreach (XmlElement node in nodeList) { BlogPost blogPost = this.Parse(node, includeCategories, result.uri); if (blogPost != null) { if (seenIds.Contains(blogPost.Id)) { throw new DuplicateEntryIdException(); } seenIds.Add(blogPost.Id); if (!now.HasValue || blogPost.DatePublished.CompareTo(now.Value) < 0) { blogPosts.Add(blogPost); } } if (blogPosts.Count >= maxPosts) { break; } } if (blogPosts.Count >= maxPosts) { break; } XmlElement nextNode = doc.SelectSingleNodeNS("/atom:feed/atom:link[@rel='next']", _nsMgr.ToNSMethodFormat()) as XmlElement; if (nextNode == null) { break; } blogId = XmlHelper.GetUrl(nextNode, "@href", result.uri); if (blogId.Length == 0) { break; } } } catch (DuplicateEntryIdException) { //if (ApplicationDiagnostics.AutomationMode) // Debug.WriteLine("Duplicate IDs detected in feed"); //else // Debug.Fail("Duplicate IDs detected in feed"); } return((BlogPost[])blogPosts.ToArray(typeof(BlogPost))); }
private async Task AddCategoriesXml(XmlElement categoriesNode, XmlElement containerNode, XmlRestRequestHelper.XmlRequestResult result) { if (categoriesNode.Attributes.Any(a => a.NodeName == "href")) { string href = XmlHelper.GetUrl(categoriesNode, "@href", result.uri); if (href != null && href.Length > 0) { Uri uri = new Uri(href); if (result.uri == null || !uri.Equals(result.uri)) // detect simple cycles { XmlDocument doc = await xmlRestRequestHelper.Get(RequestFilter, result); XmlElement categories = (XmlElement)doc.SelectSingleNodeNS(@"app:categories", _nsMgr.ToNSMethodFormat()); if (categories != null) { await AddCategoriesXml(categories, containerNode, result); } } } } else { containerNode.AppendChild(containerNode.OwnerDocument.ImportNode(categoriesNode, true)); } }